强制 Faraday 适配器 :typhoeus 使用 HTTP/2 进行请求

Ale*_*oev 1 ruby typhoeus faraday http2

如何强制Faraday适配器tyhoeus使用HTTP/2来向支持HTTP/2的服务器发出请求?我已经通过服务https://http2.pro/doc/api对此进行了测试,结果如下:

body="{\"http2\":1,\"protocol\":\"HTTP\\/2.0\",\"push\":0,\"user_agent\":\"Faraday v0.12.2\"}",
Run Code Online (Sandbox Code Playgroud)

\"http2\":1,这意味着 HTTP/2 不用于请求!

ano*_*rmh 7

这里有两件事在起作用。第一个是远程 API 在响应正文中对您撒谎。他们的文档说:

http2:可能的值为 0(使用了 HTTP/2)和 1(未使用 HTTP/2)。

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

使用了HTTP2

因此,一旦我们知道 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
Run Code Online (Sandbox Code Playgroud)

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

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
Run Code Online (Sandbox Code Playgroud)

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

response.http_version
NoMethodError: undefined method `http_version' for #<Faraday::Response:0x00007f99935519a8>
Run Code Online (Sandbox Code Playgroud)

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

response.class
=> Faraday::Response < Object
Run Code Online (Sandbox Code Playgroud)

因此,我们需要进入 gem 本身来找出它在哪里创建对象,Typhoeus::Response以便我们可以.http_version手动调用它并确认它使用我们期望的协议。事实证明,就在这里

让我们采取简单的方法并坚持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
Run Code Online (Sandbox Code Playgroud)

然后重新运行请求:

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")
Run Code Online (Sandbox Code Playgroud)

你会看到:

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
Run Code Online (Sandbox Code Playgroud)

现在输入:

response = ::Typhoeus::Request.new(env[:url].to_s, opts).run
Run Code Online (Sandbox Code Playgroud)

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

response.class
=> Typhoeus::Response < Object
Run Code Online (Sandbox Code Playgroud)

并确认它使用的是 HTTP2:

response.http_version
=> "2"
Run Code Online (Sandbox Code Playgroud)

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

response.body
=> "{\"http2\":1,\"protocol\":\"HTTP\\/2.0\",\"push\":0,\"user_agent\":\"Faraday v0.17.0\"}"
Run Code Online (Sandbox Code Playgroud)

这就是您如何使用 Typhoeus 作为 Faraday 适配器来发出 HTTP2 请求。