类 Net::HTTPSession

类 Net::HTTP 提供了一个丰富的库,该库在客户端-服务器模型中实现了客户端,该模型使用 HTTP 请求-响应协议。有关 HTTP 的信息,请参阅

关于示例

此处的示例假设已 require 了 net/http(这也 require 了 uri

require 'net/http'

此处许多代码示例使用这些示例网站

一些示例还假设这些变量

uri = URI('https://jsonplaceholder.typicode.com/')
uri.freeze # Examples may not modify.
hostname = uri.hostname # => "jsonplaceholder.typicode.com"
path = uri.path         # => "/"
port = uri.port         # => 443

以便可以将示例请求编写为

Net::HTTP.get(uri)
Net::HTTP.get(hostname, '/index.html')
Net::HTTP.start(hostname) do |http|
  http.get('/todos/1')
  http.get('/todos/2')
end

一个需要修改 URI 的示例首先复制 uri,然后修改副本

_uri = uri.dup
_uri.path = '/todos/1'

策略

上述方法是通过其少量参数允许对请求进行最少控制的便利方法。为了获得更大的控制,请考虑使用 请求对象

URI

在互联网上,URI统一资源标识符)是一个标识特定资源的字符串。它由以下部分或全部组成:方案、主机名、路径、查询和片段;请参阅 URI 语法

Ruby URI::Generic 对象表示互联网 URI。它提供了 schemehostnamepathqueryfragment 等方法。

方案

互联网 URI 有一个 方案

Net::HTTP 中支持的两个方案是 'https''http'

uri.scheme                       # => "https"
URI('http://example.com').scheme # => "http"

主机名

主机名标识一个可以向其发送请求的服务器(主机)

hostname = uri.hostname # => "jsonplaceholder.typicode.com"
Net::HTTP.start(hostname) do |http|
  # Some HTTP stuff.
end

路径

特定于主机的路径标识主机上的资源

_uri = uri.dup
_uri.path = '/todos/1'
hostname = _uri.hostname
path = _uri.path
Net::HTTP.get(hostname, path)

查询

特定于主机的查询将名称/值对添加到 URI

_uri = uri.dup
params = {userId: 1, completed: false}
_uri.query = URI.encode_www_form(params)
_uri # => #<URI::HTTPS https://jsonplaceholder.typicode.com?userId=1&completed=false>
Net::HTTP.get(_uri)

片段

URI 片段在 Net::HTTP 中不起作用;无论是否包含片段,都会返回相同的数据。

请求头

请求头可用于将附加信息传递到主机,类似于在方法调用中传递的参数;每个头都是一个名称/值对。

每个向主机发送请求的 Net::HTTP 方法都有一个可选参数 headers,其中标头表示为字段名称/值对的哈希

headers = {Accept: 'application/json', Connection: 'Keep-Alive'}
Net::HTTP.get(uri, headers)

请参阅 请求字段 中标准请求字段和常用请求字段的列表。主机也可能接受其他自定义字段。

HTTP 会话

会话是服务器(主机)和客户端之间的连接,它

请参阅 策略 中的示例会话。

使用 Net::HTTP.start 的会话

如果您要向单个主机(和端口)发出许多请求,请考虑使用带有块的单例方法 Net::HTTP.start;该方法通过以下方式自动处理会话

在块中,您可以使用这些实例方法,每个方法都会发送一个请求

使用 Net::HTTP.start 和 Net::HTTP.finish 的会话

您可以使用方法 startfinish 手动管理会话

http = Net::HTTP.new(hostname)
http.start
http.get('/todos/1')
http.get('/todos/2')
http.delete('/posts/1')
http.finish # Needed to free resources.

单请求会话

某些便利方法通过以下方式自动处理会话

发送 GET 请求的此类方法

发送 POST 请求的此类方法

HTTP 请求和响应

上面的许多方法都是便利方法,每个方法都会发送请求并返回一个字符串,而无需直接使用 Net::HTTPRequest 和 Net::HTTPResponse 对象。

但是,您可以直接创建一个请求对象,发送请求并检索响应对象;请参阅

跟随重定向

每个返回的响应都是 Net::HTTPResponse 子类的实例。请参阅 响应类层次结构

特别是,类 Net::HTTPRedirection 是所有重定向类的父类。这使您可以创建一个 case 语句来正确处理重定向

def fetch(uri, limit = 10)
  # You should choose a better exception.
  raise ArgumentError, 'Too many HTTP redirects' if limit == 0

  res = Net::HTTP.get_response(URI(uri))
  case res
  when Net::HTTPSuccess     # Any success class.
    res
  when Net::HTTPRedirection # Any redirection class.
    location = res['Location']
    warn "Redirected to #{location}"
    fetch(location, limit - 1)
  else                      # Any other class.
    res.value
  end
end

fetch(uri)

基本身份验证

基本身份验证按照 RFC2617 执行

req = Net::HTTP::Get.new(uri)
req.basic_auth('user', 'pass')
res = Net::HTTP.start(hostname) do |http|
  http.request(req)
end

流式响应体

默认情况下,Net::HTTP 会将整个响应读取到内存中。如果您正在处理大型文件或希望实现进度条,则可以改为将响应体直接流式传输到 IO

Net::HTTP.start(hostname) do |http|
  req = Net::HTTP::Get.new(uri)
  http.request(req) do |res|
    open('t.tmp', 'w') do |f|
      res.read_body do |chunk|
        f.write chunk
      end
    end
  end
end

HTTPS

通过 Net::HTTP#use_ssl= 可以为 HTTP 连接启用 HTTPS。

Net::HTTP.start(hostname, :use_ssl => true) do |http|
  req = Net::HTTP::Get.new(uri)
  res = http.request(req)
end

或者,如果您只想发出 GET 请求,则可以传入一个具有 HTTPS URL 的 URI 对象。如果 URI 对象具有 'https' URI 方案,Net::HTTP 会自动启用 TLS 验证。

uri # => #<URI::HTTPS https://jsonplaceholder.typicode.com/>
Net::HTTP.get(uri)

代理服务器

HTTP 对象可以具有一个代理服务器

您可以使用方法 Net::HTTP.new 或方法 Net::HTTP.start 创建具有代理服务器的 HTTP 对象。

代理可以通过参数 p_addr 或环境变量 'http_proxy' 来定义。

使用字符串作为参数 p_addr 的代理

当参数 p_addr 是一个字符串主机名时,返回的 http 将把给定的主机作为其代理。

http = Net::HTTP.new(hostname, nil, 'proxy.example')
http.proxy?          # => true
http.proxy_from_env? # => false
http.proxy_address   # => "proxy.example"
# These use default values.
http.proxy_port      # => 80
http.proxy_user      # => nil
http.proxy_pass      # => nil

还可以提供代理的端口、用户名和密码。

http = Net::HTTP.new(hostname, nil, 'proxy.example', 8000, 'pname', 'ppass')
# => #<Net::HTTP jsonplaceholder.typicode.com:80 open=false>
http.proxy?          # => true
http.proxy_from_env? # => false
http.proxy_address   # => "proxy.example"
http.proxy_port      # => 8000
http.proxy_user      # => "pname"
http.proxy_pass      # => "ppass"

使用 'ENV['http_proxy']' 的代理

当环境变量 'http_proxy' 设置为 URI 字符串时,返回的 http 将使用该 URI 上的服务器作为其代理;请注意,URI 字符串必须具有协议,例如 'http''https'

ENV['http_proxy'] = 'http://example.com'
http = Net::HTTP.new(hostname)
http.proxy?          # => true
http.proxy_from_env? # => true
http.proxy_address   # => "example.com"
# These use default values.
http.proxy_port      # => 80
http.proxy_user      # => nil
http.proxy_pass      # => nil

URI 字符串可以包括代理用户名、密码和端口号。

ENV['http_proxy'] = 'http://pname:ppass@example.com:8000'
http = Net::HTTP.new(hostname)
http.proxy?          # => true
http.proxy_from_env? # => true
http.proxy_address   # => "example.com"
http.proxy_port      # => 8000
http.proxy_user      # => "pname"
http.proxy_pass      # => "ppass"

过滤代理

使用方法 Net::HTTP.new(而不是 Net::HTTP.start),您可以使用参数 p_no_proxy 来过滤代理。

压缩和解压缩

Net::HTTP 在发送之前不会压缩请求的主体。

默认情况下,Net::HTTP 会将标头 'Accept-Encoding' 添加到新的 请求对象

Net::HTTP::Get.new(uri)['Accept-Encoding']
# => "gzip;q=1.0,deflate;q=0.6,identity;q=0.3"

这将请求服务器在有响应主体的情况下进行 zip 编码;服务器不是必须这样做。

如果响应具有标头 'Content-Range',则 Net::HTTP 不会自动解压缩响应主体。

否则,解压缩(或不解压缩)取决于标头 Content-Encoding 的值。

这里有什么

首先,看看其他地方有什么。Class Net::HTTP

这是方法和属性的分类摘要。

Net::HTTP 对象

会话

连接

请求

响应

代理

安全

地址和端口

HTTP 版本

调试