gpt4 book ai didi

ruby-on-rails - 如何使用 puma(线程安全)在 Rails 应用程序上动态设置 tld_length

转载 作者:行者123 更新时间:2023-12-04 04:02:21 27 4
gpt4 key购买 nike

我们有一个 Rails 应用程序可以响应多个 TLD,包括子域。其中一个域是 .co.uk. 域,因此这种情况下的 TLD 长度为 2(例如:ourapp.esourapp.co。英国api.ourapp.esapi.ourapp.co.uk

为了动态更改我们使用的 TLD 长度 this Rack middleware :

class Rack::TldLength

def initialize(app, host_pattern, host_tld_length)
@app = app
@host_pattern = Regexp.new(host_pattern)
@host_tld_length = host_tld_length
end

def call(env)
original_tld_length = tld_length

request = Rack::Request.new(env)

set_tld_length(@host_tld_length) if request.host =~ @host_pattern

@app.call(env)
ensure
set_tld_length(original_tld_length)
end

private

def tld_length
ActionDispatch::Http::URL.tld_length
end
def set_tld_length(length)
ActionDispatch::Http::URL.tld_length = length
end
end

到目前为止,这一直有效,直到我们决定从 Unicorn 迁移到 Puma。使用 Unicorn,每个请求都会发送给不同的 unicorn worker(进程),这没有问题。然而,对于 puma,每个请求都可以由不同的线程处理。我们怀疑更改值 ActionDispatch::Http::URL.tld_length 不是线程安全的,但我们正在努力寻找替代方法。

似乎 Rails 路由(我们定义具有子域约束的​​路由)取决于正确设置 ActionDispatch::Http::URL.tld_length

是否有任何变通方法来保持由多个线程提供的并发性,同时仍然能够处理具有不同 TLD 长度的多个域?

最佳答案

您声明:

It seems that the Rails routing (where we define routes with subdomain constraints) depends on setting the ActionDispatch::Http::URL.tld_length properly.

在我看来,最简单的方法是规范化 env 中的 "HOST" 参数,以允许所有主机名的行为相同。

# Place this middleware at the top of the chain, before any Rails middleware.
class Rack::FixedHost

# a host_pattern can be: /(foo.com|foo.co.uk|foo.bor.co.uk)$/
def initialize(app, host_pattern, normalized_host)
@app = app
@host_pattern = Regexp.new(host_pattern)
@normalized_host = normalized_host
end

def call(env)
env[:ORIGINAL_HOST] = env['HTTP_HOST'.freeze] || @normalized_host
env[:ORIGINAL_DOMAIN] = env[:ORIGINAL_HOST].match(@host_pattern).to_a[0] || @normalized_host
env['HTTP_HOST'.freeze] = env[:ORIGINAL_HOST].to_s.sub(@host_pattern, @normalized_host)
@app.call(env)
end
end

澄清一下:规范化主机意味着它始终具有相同的主机名后缀,而不管原始后缀如何,从而可以更轻松地提取子域。

即,对于 sub.foo.comsub.foo.co.uksub.foo.bor.co.uk normalized_host 将始终是 sub.foo.com

在此示例中,sub 很容易在不同的主机变体(foo.comfoo.co.uk >foo.bor.co.uk) 都已标准化为单个“标准化”变体 (foo.com)。

默认情况下,url_for 等方法将构造一个相对 URL,因此实际的主机名并不重要。

但是,如果您使用 url_for或其他功能来提供完整的 URL,您可以考虑使用显式 :host 将流量定向到您正在使用的区域主机名。即:

url_for(action: 'index', host: "admin.#{request.env[:ORIGINAL_DOMAIN]}")

当然,这可以通过在标准化主机之前提取原始域名来变得更加强大,允许您在保留区域域的同时路由到特定的子域。


注意(我原来的观察/回答):

您的代码将每个请求的 TLD 长度存储在一个共享的全局变量中。

当两个并行请求到达时,在两个不同的线程上,很可能知道将使用哪个 TLD 长度(如果没有数据“剪切”发生,则很可能是最后写入的一个)。

线程安全的方法会将信息存储在 env 变量中,允许每个请求都有自己的 TLD 长度。

以下示例将不起作用,因为我不处理 TLD 长度并且不知道如何计算它们......但它显示了 env 作为线程安全的使用-请求存储。

class Rack::TldLength

def initialize(app, host_pattern, host_tld_length)
@app = app
@host_pattern = Regexp.new(host_pattern)
@default_tld_length = host_tld_length
end

def call(env)
# ActionDispatch::Http::URL.tld_length = @default_tld_length if(env["HTTP_HOST".freeze].to_s =~ @host_pattern)
env[:hosts_tld] = (env["HTTP_HOST".freeze].to_s =~ @host_pattern) ? @default_tld_length : ActionDispatch::Http::URL.tld_length
@app.call(env)
end
end

关于ruby-on-rails - 如何使用 puma(线程安全)在 Rails 应用程序上动态设置 tld_length,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62899816/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com