class Net::HTTP

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

关于示例

此处的示例假设已加载 net/http(这也将加载 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)

片段

Net::HTTP 中 URI 片段 没有影响;无论是否包含片段,都会返回相同的数据。

请求头

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

此类的每个将请求发送到主机的 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 对象。Net::HTTP 会自动开启 TLS 验证,如果 URI 对象具有 'https' URI 方案

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 头的值

这里有什么

首先,其他内容。类 Net::HTTP

这是一个按类别分类的方法和属性的摘要。

Net::HTTP 对象

会话

连接

请求

响应

代理

Security

地址和端口

HTTP 版本

调试