强制法拉第适配器 :typhoeus 对请求使用 HTTP/2

enforcing Faraday adapter :typhoeus to use HTTP/2 for requests

如何强制 Faraday 适配器 typhoeus 对支持 HTTP/2 的服务器的请求使用 HTTP/2? 我已经通过服务 https://http2.pro/doc/api 测试了这个,结果是这样的:

body="{\"http2\":1,\"protocol\":\"HTTP\/2.0\",\"push\":0,\"user_agent\":\"Faraday v0.12.2\"}",

\"http2\":1, 什么意思 HTTP/2 不用于请求!

这里有两件事在起作用。首先是 remote API 在响应正文中对你撒谎。他们的文档说:

http2: Possible values are 0 (HTTP/2 was used) and 1 (HTTP/2 was not used).

尽管响应正文显示 'http2': 1 表示未使用 HTTP2,但 正在使用 。您可以使用 Chrome 的开发工具最轻松地确认这一点:

所以一旦我们知道 API 位于响应正文中,我们如何独立确认 Typhoeus 使用的是 HTTP2?

(此答案假设您使用 pry 作为 REPL,而不是 IRB)

首先让我们确认 Typhoeus 单独使用 HTTP2:

require 'typhoeus'
response = Typhoeus.get("https://http2.pro/api/v1", http_version: :httpv2_0)
response.class
=> Typhoeus::Response < Object
response.body
=> "{\"http2\":1,\"protocol\":\"HTTP\/2.0\",\"push\":0,\"user_agent\":\"Typhoeus - https:\/\/github.com\/typhoeus\/typhoeus\"}" # this is the lying API response
response.http_version
=> "2" # this is what Typhoeus tells us was actually used

现在让我们在法拉第测试一下:

require 'faraday'
require 'typhoeus'
require 'typhoeus/adapters/faraday'

conn = Faraday.new do |faraday|
  faraday.adapter :typhoeus, http_version: :httpv2_0
end

response = conn.get("https://http2.pro/api/v1")
response.body
=> "{\"http2\":1,\"protocol\":\"HTTP\/2.0\",\"push\":0,\"user_agent\":\"Faraday v0.17.0\"}" # again we get the lying API response

但是我们如何确认它是 HTTP2?这不起作用:

response.http_version
NoMethodError: undefined method `http_version' for #<Faraday::Response:0x00007f99935519a8>

因为 response 不是 Typhoeus::Response 物体,它是法拉第物体:

response.class
=> Faraday::Response < Object

所以我们需要进入 gem 本身,找出它在哪里创建 Typhoeus::Response 对象,这样我们就可以手动调用 .http_version 并确认它正在使用我们的协议预计。事实证明,那是 right here.

让我们走简单的路线,将 binding.pry 粘贴到 gem 的本地副本中(您需要重新启动 pry 以获取对 gem 的更改):

  def typhoeus_request(env)
    opts = {
      :method => env[:method],
      :body => env[:body],
      :headers => env[:request_headers]
    }.merge(@adapter_options)
    binding.pry
    ::Typhoeus::Request.new(env[:url].to_s, opts)
  end

然后重新运行请求:

require 'faraday'
require 'typhoeus'
require 'typhoeus/adapters/faraday'

conn = Faraday.new do |faraday|
  faraday.adapter :typhoeus, http_version: :httpv2_0
end

response = conn.get("https://http2.pro/api/v1")

你会看到:

Frame number: 0/3

From: /Users/foo/.rvm/gems/ruby-2.6.3/gems/typhoeus-1.3.1/lib/typhoeus/adapters/faraday.rb @ line 127 Faraday::Adapter::Typhoeus#typhoeus_request:

    120: def typhoeus_request(env)
    121:   opts = {
    122:     :method => env[:method],
    123:     :body => env[:body],
    124:     :headers => env[:request_headers]
    125:   }.merge(@adapter_options)
    126:   binding.pry
 => 127:   ::Typhoeus::Request.new(env[:url].to_s, opts)
    128: end

现在输入:

response = ::Typhoeus::Request.new(env[:url].to_s, opts).run

并确认它是一个 Typhoeus::Response 对象:

response.class
=> Typhoeus::Response < Object

并确认它使用的是 HTTP2:

response.http_version
=> "2"

并确认 API 响应正文是一个肮脏的骗子:

response.body
=> "{\"http2\":1,\"protocol\":\"HTTP\/2.0\",\"push\":0,\"user_agent\":\"Faraday v0.17.0\"}"

这就是您将 Typhoeus 用作法拉第适配器来发出 HTTP2 请求的方式。