为什么 Net::HTTP 在服务器返回 503 时返回 500?
Why is Net::HTTP returning a 500 when the server is returning a 503?
(这个问题取代了this one,希望有更好的信息。)
我准备了三台服务器,我将它们分别称为 Alice、Charlie 和 Harry(Harry 是服务器的真实昵称,以免混淆)。他们都互相交谈以执行相当复杂的身份验证流程:
- 客户端通过 Alice 向 Harry 执行一系列三个请求。
- 第三次,Harry 给 Charlie 打了电话。
- 查理在交通繁忙期间很容易超时。如果是,Harry returns a
503
with a Retry-After
header to Alice.
- Harry 是返回一个
503
,我已经在它自己的日志中确认了这一点。
- Alice 收到的不是
503
,而是 500
、,但没有 header.
- 爱丽丝的其他客户(我无法控制)对
500
的处理与对其他错误的处理相同,这正是我最终要解决的问题。
一些额外的信息,例如我已经能够确定的:
- Alice 使用
RestClient
代理调用 Harry,后者在后台使用 Net::HTTP
。
- 直接使用
Net::HTTP
得到相同的结果。
- 它不是特定于环境的;我在生产和开发中都遇到过这个问题。
- 我一直在尝试使用 Postman 模拟爱丽丝,但还没有成功;目前 Charlie 的流量比较安静,我无法强制或模拟超时,到目前为止我只从 Harry 那里获得了成功的
200
响应。
- 修复查理的超时显然是理想的,但我也无法控制查理的硬件。
有什么我可以改变 Alice 的地方,以便它正确检测到 Harry 的 503
?
或者,是否有可能关于 Harry 的某些东西在返回并记录后将其 503
更改为 500
?
这是爱丽丝第三次通话的代码,如果它可能有帮助的话,但我没有什么特别的;我一直想知道 RestClient
或 Net::HTTP
是否有一些我不知道的配置。
http_verb = :post
args = [ # actually constructed differently, but this is a reasonable mock up
'https://api.harry/path?sso_token=token',
'',
{
'content_type' => 'application/json',
'accept' => '*/*',
# some other app-specific headers
}
]
RestClient.send(http_verb, *args) do |response, request, result, &block|
# `result` is present and has a 500 code at the start of this block if Harry returns a 503.
@status_code = result.present? ? result.code : :internal_server_error
cors.merge!( response.headers.slice(:access_control_allow_origin, :access_control_request_method) )
@body = response.body
end
事实证明,这方式比任何人想象的都更简单、更明显。
在负责返回 503
的中间件中引发了 单独的 错误。与任何其他异常一样,它呈现为 500
.
导致它的是一行本应告诉客户端等待五秒钟然后重试的行:
response.headers['Retry-After'] = 5
...一些中间件组件抱怨 undefined method 'each' on 5:Fixnum
,因为它期待一个不是字符串的数组;当我们将 5
更改为 '5'
.
时它开始工作
(这个问题取代了this one,希望有更好的信息。)
我准备了三台服务器,我将它们分别称为 Alice、Charlie 和 Harry(Harry 是服务器的真实昵称,以免混淆)。他们都互相交谈以执行相当复杂的身份验证流程:
- 客户端通过 Alice 向 Harry 执行一系列三个请求。
- 第三次,Harry 给 Charlie 打了电话。
- 查理在交通繁忙期间很容易超时。如果是,Harry returns a
503
with aRetry-After
header to Alice. - Harry 是返回一个
503
,我已经在它自己的日志中确认了这一点。 - Alice 收到的不是
503
,而是500
、,但没有 header. - 爱丽丝的其他客户(我无法控制)对
500
的处理与对其他错误的处理相同,这正是我最终要解决的问题。
一些额外的信息,例如我已经能够确定的:
- Alice 使用
RestClient
代理调用 Harry,后者在后台使用Net::HTTP
。 - 直接使用
Net::HTTP
得到相同的结果。 - 它不是特定于环境的;我在生产和开发中都遇到过这个问题。
- 我一直在尝试使用 Postman 模拟爱丽丝,但还没有成功;目前 Charlie 的流量比较安静,我无法强制或模拟超时,到目前为止我只从 Harry 那里获得了成功的
200
响应。 - 修复查理的超时显然是理想的,但我也无法控制查理的硬件。
有什么我可以改变 Alice 的地方,以便它正确检测到 Harry 的 503
?
或者,是否有可能关于 Harry 的某些东西在返回并记录后将其 503
更改为 500
?
这是爱丽丝第三次通话的代码,如果它可能有帮助的话,但我没有什么特别的;我一直想知道 RestClient
或 Net::HTTP
是否有一些我不知道的配置。
http_verb = :post
args = [ # actually constructed differently, but this is a reasonable mock up
'https://api.harry/path?sso_token=token',
'',
{
'content_type' => 'application/json',
'accept' => '*/*',
# some other app-specific headers
}
]
RestClient.send(http_verb, *args) do |response, request, result, &block|
# `result` is present and has a 500 code at the start of this block if Harry returns a 503.
@status_code = result.present? ? result.code : :internal_server_error
cors.merge!( response.headers.slice(:access_control_allow_origin, :access_control_request_method) )
@body = response.body
end
事实证明,这方式比任何人想象的都更简单、更明显。
在负责返回 503
的中间件中引发了 单独的 错误。与任何其他异常一样,它呈现为 500
.
导致它的是一行本应告诉客户端等待五秒钟然后重试的行:
response.headers['Retry-After'] = 5
...一些中间件组件抱怨 undefined method 'each' on 5:Fixnum
,因为它期待一个不是字符串的数组;当我们将 5
更改为 '5'
.