首页 > 解决方案 > 强制法拉第适配器 :typhoeus 使用 HTTP/2 进行请求

问题描述

如何强制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 不用于请求!

标签: rubyhttp2faradaytyphoeus

解决方案


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

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

尽管响应正文显示'http2': 1HTTP2 未被使用,但它正在被使用。您可以使用 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

现在让我们在法拉第测试它:

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它并确认它使用我们期望的协议。事实证明,就在这里

让我们采取简单的方法并坚持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 请求。


推荐阅读