类 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'
策略¶ ↑
-
如果你只需要发送几个 GET 请求,可以考虑使用
OpenURI
。 -
如果你只需要发送少量各种类型的请求,可以考虑使用此类中的各种单例便捷方法。以下每个方法都会自动启动并完成一个发送单个请求的 会话
# Return string response body. Net::HTTP.get(hostname, path) Net::HTTP.get(uri) # Write string response body to $stdout. Net::HTTP.get_print(hostname, path) Net::HTTP.get_print(uri) # Return response as Net::HTTPResponse object. Net::HTTP.get_response(hostname, path) Net::HTTP.get_response(uri) data = '{"title": "foo", "body": "bar", "userId": 1}' Net::HTTP.post(uri, data) params = {title: 'foo', body: 'bar', userId: 1} Net::HTTP.post_form(uri, params)
-
如果性能很重要,可以考虑使用会话,这可以降低请求开销。此 会话 包含多个针对 HTTP 方法 和 WebDAV 方法 的请求。
Net::HTTP.start(hostname) do |http| # Session started automatically before block execution. http.get(path) http.head(path) body = 'Some text' http.post(path, body) # Can also have a block. http.put(path, body) http.delete(path) http.options(path) http.trace(path) http.patch(path, body) # Can also have a block. http.copy(path) http.lock(path, body) http.mkcol(path, body) http.move(path) http.propfind(path, body) http.proppatch(path, body) http.unlock(path, body) # Session finished automatically at block exit. end
上面提到的方法是便捷方法,它们通过少量参数允许对请求进行最少的控制。为了获得更大的控制,可以考虑使用 请求对象。
URI¶ ↑
在互联网上,URI
(统一资源标识符)是一个标识特定资源的字符串。它包含一些或所有以下内容:方案、主机名、路径、查询和片段;请参阅 URI 语法。
一个 Ruby URI::Generic
对象表示一个互联网 URI
。它提供了 scheme
、hostname
、path
、query
和 fragment
等方法。
方案¶ ↑
一个互联网 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#finish
结束。
请参阅 策略 中的示例会话。
使用 Net::HTTP.start 的会话¶ ↑
如果您需要向单个主机(和端口)发送多个请求,请考虑使用单例方法 Net::HTTP.start
和一个代码块;该方法会通过以下方式自动处理会话:
在代码块中,您可以使用以下实例方法,每个方法都会发送单个请求。
-
-
get
,request_get
: GET。 -
head
,request_head
: HEAD。 -
post
,request_post
: POST。 -
delete
: DELETE。 -
options
: OPTIONS。 -
trace
: TRACE。 -
patch
: PATCH。
-
使用 Net::HTTP.start 和 Net::HTTP.finish 的会话¶ ↑
您可以使用方法 start
和 finish
手动管理会话。
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.
单请求会话¶ ↑
某些便捷方法会自动处理会话,方法是:
-
创建 HTTP 对象
-
启动会话。
-
发送单个请求。
-
结束会话。
-
销毁对象。
发送 GET 请求的此类方法
-
::get
: 返回字符串响应主体。 -
::get_print
: 将字符串响应主体写入 $stdout。 -
::get_response
: 返回一个Net::HTTPResponse
对象。
发送 POST 请求的此类方法
-
::post
: 将数据发布到主机。 -
::post_form
: 将表单数据发布到主机。
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:[email protected]: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
过滤代理。
-
拒绝特定地址。
http = Net::HTTP.new('example.com', nil, 'proxy.example', 8000, 'pname', 'ppass', 'proxy.example') http.proxy_address # => nil
-
拒绝特定域名或子域名。
http = Net::HTTP.new('example.com', nil, 'my.proxy.example', 8000, 'pname', 'ppass', 'proxy.example') http.proxy_address # => nil
-
拒绝特定地址和端口组合。
http = Net::HTTP.new('example.com', nil, 'proxy.example', 8000, 'pname', 'ppass', 'proxy.example:1234') http.proxy_address # => "proxy.example" http = Net::HTTP.new('example.com', nil, 'proxy.example', 8000, 'pname', 'ppass', 'proxy.example:8000') http.proxy_address # => nil
-
拒绝使用逗号分隔的上述类型列表。
http = Net::HTTP.new('example.com', nil, 'proxy.example', 8000, 'pname', 'ppass', 'my.proxy,proxy.example:8000') http.proxy_address # => nil http = Net::HTTP.new('example.com', nil, 'my.proxy', 8000, 'pname', 'ppass', 'my.proxy,proxy.example:8000') http.proxy_address # => nil
压缩和解压缩¶ ↑
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 的值。
-
'deflate'
、'gzip'
或'x-gzip'
:解压缩主体并删除标头。 -
'none'
或'identity'
:不解压缩主体,但删除标头。 -
任何其他值:保持主体和标头不变。
这里有什么¶ ↑
这是方法和属性的分类摘要。
Net::HTTP 对象¶ ↑
会话¶ ↑
连接¶ ↑
-
:continue_timeout:返回继续超时。
-
#continue_timeout=:设置继续超时秒数。
-
:keep_alive_timeout:返回保持活动超时。
-
:keep_alive_timeout=:设置保持活动超时。
-
:max_retries:返回最大重试次数。
-
#max_retries=:设置最大重试次数。
-
:open_timeout:返回打开超时。
-
:open_timeout=: 设置打开超时时间。
-
:read_timeout: 返回打开超时时间。
-
:read_timeout=: 设置读取超时时间。
-
:ssl_timeout: 返回 ssl 超时时间。
-
:ssl_timeout=: 设置 ssl 超时时间。
-
:write_timeout: 返回写入超时时间。
-
write_timeout=: 设置写入超时时间。
请求¶ ↑
-
::get: 发送 GET 请求并返回字符串响应主体。
-
::get_print: 发送 GET 请求并将字符串响应主体写入 $stdout。
-
::get_response: 发送 GET 请求并返回响应对象。
-
::post_form: 发送带有表单数据的 POST 请求并返回响应对象。
-
::post: 发送带有数据的 POST 请求并返回响应对象。
-
#copy: 发送 COPY 请求并返回响应对象。
-
#delete: 发送 DELETE 请求并返回响应对象。
-
#get: 发送 GET 请求并返回响应对象。
-
#head: 发送 HEAD 请求并返回响应对象。
-
#lock: 发送 LOCK 请求并返回响应对象。
-
#mkcol: 发送 MKCOL 请求并返回响应对象。
-
#move: 发送 MOVE 请求并返回响应对象。
-
#options: 发送 OPTIONS 请求并返回响应对象。
-
#patch: 发送 PATCH 请求并返回响应对象。
-
#post: 发送 POST 请求并返回响应对象。
-
#propfind: 发送 PROPFIND 请求并返回响应对象。
-
#proppatch: 发送 PROPPATCH 请求并返回响应对象。
-
#put: 发送 PUT 请求并返回响应对象。
-
#request: 发送请求并返回响应对象。
-
#request_get (别名为 #get2): 发送 GET 请求并形成响应对象;如果给定块,则使用该对象调用块,否则返回该对象。
-
#request_head (别名为 #head2): 发送 HEAD 请求并形成响应对象;如果给定块,则使用该对象调用块,否则返回该对象。
-
#request_post (别名为 #post2): 发送 POST 请求并形成响应对象;如果给定块,则使用该对象调用块,否则返回该对象。
-
#send_request: 发送请求并返回响应对象。
-
#trace: 发送 TRACE 请求并返回响应对象。
-
#unlock: 发送 UNLOCK 请求并返回响应对象。
响应¶ ↑
-
:close_on_empty_response: 返回是否在空响应时关闭连接。
-
:close_on_empty_response=: 设置是否在空响应时关闭连接。
-
:ignore_eof: 返回是否在使用
Content-Length
标头读取响应主体时忽略文件结尾。 -
:ignore_eof=: 设置是否在使用
Content-Length
标头读取响应主体时忽略文件结尾。 -
:response_body_encoding: 返回用于响应主体的编码。
-
#response_body_encoding=: 设置响应主体编码。
代理¶ ↑
-
:proxy_address: 返回代理地址。
-
:proxy_address=: 设置代理地址。
-
::proxy_class?: 返回
self
是否是代理类。 -
#proxy?: 返回
self
是否有代理。 -
#proxy_address (别名为 #proxyaddr): 返回代理地址。
-
#proxy_from_env?: 返回代理是否来自环境变量。
-
:proxy_from_env=: 设置代理是否来自环境变量。
-
:proxy_pass: 返回代理密码。
-
:proxy_pass=: 设置代理密码。
-
:proxy_port: 返回代理端口。
-
:proxy_port=: 设置代理端口。
-
#proxy_user: 返回代理用户名。
-
:proxy_user=: 设置代理用户。
安全¶ ↑
-
:ca_file: 返回 CA 证书文件的路径。
-
:ca_file=: 设置 CA 证书文件的路径。
-
:ca_path: 返回包含证书文件的 CA 目录的路径。
-
:ca_path=: 设置包含证书文件的 CA 目录的路径。
-
:cert: 返回用于客户端证书的
OpenSSL::X509::Certificate
对象。 -
:cert=: 设置用于客户端证书的
OpenSSL::X509::Certificate
对象。 -
:cert_store: 返回用于验证对等证书的 X509::Store。
-
:cert_store=: 设置用于验证对等证书的 X509::Store。
-
:ciphers: 返回可用的 SSL 密码。
-
:ciphers=: 设置可用的 SSL 密码。
-
:extra_chain_cert: 返回要添加到证书链的额外 X509 证书。
-
:extra_chain_cert=: 设置要添加到证书链的额外 X509 证书。
-
:key: 返回
OpenSSL::PKey::RSA
或OpenSSL::PKey::DSA
对象。 -
:key=: 设置
OpenSSL::PKey::RSA
或OpenSSL::PKey::DSA
对象。 -
:max_version: 返回最大 SSL 版本。
-
:max_version=: 设置最大 SSL 版本。
-
:min_version: 返回最小 SSL 版本。
-
:min_version=: 设置最小 SSL 版本。
-
#peer_cert: 返回会话套接字对等的 X509 证书链。
-
:ssl_version: 返回 SSL 版本。
-
:ssl_version=: 设置 SSL 版本。
-
#use_ssl=: 设置新会话是否使用传输层安全。
-
#use_ssl?: 返回
self
是否使用 SSL。 -
:verify_callback: 返回服务器证书验证的回调函数。
-
:verify_callback=: 设置服务器证书验证的回调函数。
-
:verify_depth: 返回证书链验证的最大深度。
-
:verify_depth=: 设置证书链验证的最大深度。
-
:verify_hostname: 返回 SSL/TLS 会话开始时服务器证书验证的标志。
-
:verify_hostname=: 设置 SSL/TLS 会话开始时服务器证书验证的标志。
-
:verify_mode: 返回 SSL/TLS 会话开始时服务器证书验证的标志。
-
:verify_mode=: 设置 SSL/TLS 会话开始时服务器证书验证的标志。
地址和端口¶ ↑
-
:address: 返回字符串主机名或主机 IP。
-
::default_port: 返回整数 80,这是用于
HTTP
请求的默认端口。 -
::http_default_port: 返回整数 80,这是用于
HTTP
请求的默认端口。 -
::https_default_port: 返回整数 443,这是用于 HTTPS 请求的默认端口。
-
#ipaddr: 返回连接的 IP 地址。
-
#ipaddr=: 设置连接的 IP 地址。
-
:local_host: 返回用于建立连接的字符串本地主机。
-
:local_host=: 设置用于建立连接的字符串本地主机。
-
:local_port: 返回用于建立连接的整数本地端口。
-
:local_port=: 设置用于建立连接的整数本地端口。
-
:port: 返回整数端口号。
HTTP 版本¶ ↑
-
::version_1_2? (别名为 ::is_version_1_2? 和 ::version_1_2): 返回 true; 保留以保持兼容性。
调试¶ ↑
-
#set_debug_output: 设置调试输出流。
属性
返回代理主机地址,如果不存在则返回 nil
;参见 Net::HTTP
中的代理服务器。
返回访问代理的密码,如果不存在则返回 nil
;参见 Net::HTTP
中的代理服务器。
返回代理主机的端口号,如果不存在则返回 nil
;参见 Net::HTTP
中的代理服务器。
返回访问代理的用户名,如果不存在则返回 nil
;参见 Net::HTTP
中的代理服务器。
返回在 ::new
中作为参数 address
给出的字符串主机名或主机 IP。
设置或返回 PEM 格式的 CA 证书文件路径。
设置或返回包含 PEM 格式证书文件的 CA 目录路径。
设置或返回用于客户端证书的 OpenSSL::X509::Certificate
对象。
设置或返回用于验证对等证书的 X509::Store。
设置或返回可用的 SSL 密码。参见 OpenSSL::SSL::SSLContext#ciphers=。
设置或返回响应为空时是否关闭连接;初始值为 false
。
返回继续超时值;请参阅 continue_timeout
=。
设置或返回要添加到证书链中的额外 X509 证书。请参阅 OpenSSL::SSL::SSLContext#add_certificate
。
设置或返回是否在使用 Content-Length
标头读取响应主体时忽略文件结尾;最初为 true
。
设置或返回发送请求后保持连接打开的秒数(整数或浮点数);最初为 2。如果在给定时间间隔内发出新请求,则将使用仍处于打开状态的连接;否则,连接将已关闭,并将打开新连接。
设置或返回 OpenSSL::PKey::RSA
或 OpenSSL::PKey::DSA
对象。
设置或返回用于建立连接的字符串本地主机;最初为 nil
。
设置或返回用于建立连接的整数本地端口;最初为 nil
。
返回重试幂等请求的最大次数;请参阅 max_retries=
。
设置或返回最大 SSL 版本。请参阅 OpenSSL::SSL::SSLContext#max_version=。
设置或返回最小 SSL 版本。请参阅 OpenSSL::SSL::SSLContext#min_version=。
设置或返回连接打开等待的秒数(整数或浮点数);初始值为 60。如果在给定时间间隔内未建立连接,则会引发异常。
返回在 ::new
中作为参数 port
给出的整数端口号。
设置代理地址;参见 代理服务器。
设置是否从环境变量 ‘ENV['http_proxy']
’ 中确定代理;参见 使用 ENV[‘http_proxy’] 的代理。
设置代理密码;参见 代理服务器。
设置代理端口;参见 代理服务器。
设置代理用户;参见 代理服务器。
返回等待读取一个块(通过一个 read(2) 调用)的秒数(整数或浮点数);参见 read_timeout=
。
返回用于响应主体编码的编码;参见 response_body_encoding=
。
设置或返回 SSL 超时秒数。
设置或返回 SSL 版本。参见 OpenSSL::SSL::SSLContext#ssl_version=。
设置或返回服务器证书验证的回调函数。
设置或返回证书链验证的最大深度。
设置或返回是否验证服务器证书对主机名的有效性。请参阅 OpenSSL::SSL::SSLContext#verify_hostname=。
设置或返回在 SSL/TLS 会话开始时进行服务器证书验证的标志。OpenSSL::SSL::VERIFY_NONE 或 OpenSSL::SSL::VERIFY_PEER 是可接受的。
返回等待写入一个块(通过一次 write(2) 调用)的数值(整数或浮点数)秒数;请参阅 write_timeout=
。
公共类方法
返回整数 80
,这是用于 HTTP 请求的默认端口。
Net::HTTP.default_port # => 80
# File lib/net/http.rb, line 900 def HTTP.default_port http_default_port() end
发送 GET 请求并返回 HTTP 响应正文作为字符串。
使用字符串参数 hostname
和 path
hostname = 'jsonplaceholder.typicode.com' path = '/todos/1' puts Net::HTTP.get(hostname, path)
输出
{ "userId": 1, "id": 1, "title": "delectus aut autem", "completed": false }
使用 URI
对象 uri
和可选的哈希参数 headers
uri = URI('https://jsonplaceholder.typicode.com/todos/1') headers = {'Content-type' => 'application/json; charset=UTF-8'} Net::HTTP.get(uri, headers)
相关
-
Net::HTTP::Get
: HTTP 方法GET
的请求类。 -
Net::HTTP#get
: HTTP 方法GET
的便捷方法。
# File lib/net/http.rb, line 802 def HTTP.get(uri_or_host, path_or_headers = nil, port = nil) get_response(uri_or_host, path_or_headers, port).body end
与 Net::HTTP.get
相似,但将返回的正文写入 $stdout;返回 nil
。
# File lib/net/http.rb, line 761 def HTTP.get_print(uri_or_host, path_or_headers = nil, port = nil) get_response(uri_or_host, path_or_headers, port) {|res| res.read_body do |chunk| $stdout.print chunk end } nil end
与 Net::HTTP.get
相似,但返回一个 Net::HTTPResponse
对象,而不是正文字符串。
# File lib/net/http.rb, line 812 def HTTP.get_response(uri_or_host, path_or_headers = nil, port = nil, &block) if path_or_headers && !path_or_headers.is_a?(Hash) host = uri_or_host path = path_or_headers new(host, port || HTTP.default_port).start {|http| return http.request_get(path, &block) } else uri = uri_or_host headers = path_or_headers start(uri.hostname, uri.port, :use_ssl => uri.scheme == 'https') {|http| return http.request_get(uri, headers, &block) } end end
返回整数 80
,这是用于 HTTP 请求的默认端口。
Net::HTTP.http_default_port # => 80
# File lib/net/http.rb, line 908 def HTTP.http_default_port 80 end
返回整数 443
,这是用于 HTTPS 请求的默认端口。
Net::HTTP.https_default_port # => 443
# File lib/net/http.rb, line 916 def HTTP.https_default_port 443 end
返回一个新的 Net::HTTP 对象 http
(但不打开 TCP 连接或 HTTP 会话)。
仅给出字符串参数 address
(且 ENV['http_proxy']
未定义或为 nil
),返回的 http
-
具有给定的地址。
-
具有默认端口号,
Net::HTTP.default_port
(80)。 -
没有代理。
示例
http = Net::HTTP.new(hostname) # => #<Net::HTTP jsonplaceholder.typicode.com:80 open=false> http.address # => "jsonplaceholder.typicode.com" http.port # => 80 http.proxy? # => false
也给出整数参数 port
,返回的 http
具有给定的端口
http = Net::HTTP.new(hostname, 8000) # => #<Net::HTTP jsonplaceholder.typicode.com:8000 open=false> http.port # => 8000
对于代理定义参数 p_addr
到 p_no_proxy
,请参阅 代理服务器。
# File lib/net/http.rb, line 1065 def HTTP.new(address, port = nil, p_addr = :ENV, p_port = nil, p_user = nil, p_pass = nil, p_no_proxy = nil) http = super address, port if proxy_class? then # from Net::HTTP::Proxy() http.proxy_from_env = @proxy_from_env http.proxy_address = @proxy_address http.proxy_port = @proxy_port http.proxy_user = @proxy_user http.proxy_pass = @proxy_pass elsif p_addr == :ENV then http.proxy_from_env = true else if p_addr && p_no_proxy && !URI::Generic.use_proxy?(address, address, port, p_no_proxy) p_addr = nil p_port = nil end http.proxy_address = p_addr http.proxy_port = p_port || default_port http.proxy_user = p_user http.proxy_pass = p_pass end http end
将数据发布到主机;返回一个 Net::HTTPResponse
对象。
参数 url
必须是 URL;参数 data
必须是字符串
_uri = uri.dup _uri.path = '/posts' data = '{"title": "foo", "body": "bar", "userId": 1}' headers = {'content-type': 'application/json'} res = Net::HTTP.post(_uri, data, headers) # => #<Net::HTTPCreated 201 Created readbody=true> puts res.body
输出
{ "title": "foo", "body": "bar", "userId": 1, "id": 101 }
相关
-
Net::HTTP::Post
: HTTP 方法POST
的请求类。 -
Net::HTTP#post
: HTTP 方法POST
的便捷方法。
# File lib/net/http.rb, line 855 def HTTP.post(url, data, header = nil) start(url.hostname, url.port, :use_ssl => url.scheme == 'https' ) {|http| http.post(url, data, header) } end
将数据发布到主机;返回一个 Net::HTTPResponse
对象。
参数 url
必须是 URI
;参数 data
必须是哈希表
_uri = uri.dup _uri.path = '/posts' data = {title: 'foo', body: 'bar', userId: 1} res = Net::HTTP.post_form(_uri, data) # => #<Net::HTTPCreated 201 Created readbody=true> puts res.body
输出
{ "title": "foo", "body": "bar", "userId": "1", "id": 101 }
# File lib/net/http.rb, line 882 def HTTP.post_form(url, params) req = Post.new(url) req.form_data = params req.basic_auth url.user, url.password if url.user start(url.hostname, url.port, :use_ssl => url.scheme == 'https' ) {|http| http.request(req) } end
如果 self 是由 HTTP::Proxy 创建的类,则返回 true。
# File lib/net/http.rb, line 1762 def proxy_class? defined?(@is_proxy_class) ? @is_proxy_class : false end
通过 Net::HTTP.new 创建一个新的 Net::HTTP 对象 http
。
-
对于参数
address
和port
,请参阅Net::HTTP.new
。 -
对于代理定义参数
p_addr
到p_pass
,请参阅 代理服务器。 -
对于参数
opts
,请参阅下文。
没有给出代码块
-
调用 `http.start` 而不带块(参见
start
),这将打开一个 TCP 连接和 HTTP 会话。 -
返回 `http`。
-
调用者应调用
finish
来关闭会话。http = Net::HTTP.start(hostname) http.started? # => true http.finish http.started? # => false
如果给定块
-
调用 `http.start` 带有块(参见
start
),这将-
打开一个 TCP 连接和 HTTP 会话。
-
调用块,该块可能对主机发出任意数量的请求。
-
在块退出时关闭 HTTP 会话和 TCP 连接。
-
返回块的值 `object`。
-
-
返回 `object`。
示例
hostname = 'jsonplaceholder.typicode.com' Net::HTTP.start(hostname) do |http| puts http.get('/todos/1').body puts http.get('/todos/2').body end
输出
{ "userId": 1, "id": 1, "title": "delectus aut autem", "completed": false } { "userId": 1, "id": 2, "title": "quis ut nam facilis et officia qui", "completed": false }
如果给定的最后一个参数是哈希,则它是 `opts` 哈希,其中每个键都是要调用的方法或访问器,其值是要设置的值。
键可能包括
注意:如果 `port` 为 `nil` 且 `opts[:use_ssl]` 为真值,则传递给 `new` 的值为 Net::HTTP.https_default_port
,而不是 `port`。
# File lib/net/http.rb, line 1010 def HTTP.start(address, *arg, &block) # :yield: +http+ arg.pop if opt = Hash.try_convert(arg[-1]) port, p_addr, p_port, p_user, p_pass = *arg p_addr = :ENV if arg.size < 2 port = https_default_port if !port && opt && opt[:use_ssl] http = new(address, port, p_addr, p_port, p_user, p_pass) http.ipaddr = opt[:ipaddr] if opt && opt[:ipaddr] if opt if opt[:use_ssl] opt = {verify_mode: OpenSSL::SSL::VERIFY_PEER}.update(opt) end http.methods.grep(/\A(\w+)=\z/) do |meth| key = $1.to_sym opt.key?(key) or next http.__send__(meth, opt[key]) end end http.start(&block) end
返回 `true`;保留以保持兼容性。
# File lib/net/http.rb, line 736 def HTTP.version_1_2 true end
返回 `true`;保留以保持兼容性。
# File lib/net/http.rb, line 741 def HTTP.version_1_2? true end
公共实例方法
设置继续超时值,即等待预期 100 Continue 响应的秒数。如果 HTTP 对象在这么多秒内未收到响应,它将发送请求主体。
# File lib/net/http.rb, line 1380 def continue_timeout=(sec) @socket.continue_timeout = sec if @socket @continue_timeout = sec end
向服务器发送 COPY 请求;返回一个 Net::HTTPResponse
子类的实例。
该请求基于从字符串 path
和初始头信息哈希 initheader
创建的 Net::HTTP::Copy
对象。
http = Net::HTTP.new(hostname) http.copy('/todos/1')
# File lib/net/http.rb, line 2123 def copy(path, initheader = nil) request(Copy.new(path, initheader)) end
向服务器发送 DELETE 请求;返回一个 Net::HTTPResponse
子类的实例。
该请求基于从字符串 path
和初始头信息哈希 initheader
创建的 Net::HTTP::Delete
对象。
http = Net::HTTP.new(hostname) http.delete('/todos/1')
# File lib/net/http.rb, line 2097 def delete(path, initheader = {'Depth' => 'Infinity'}) request(Delete.new(path, initheader)) end
结束 HTTP 会话
http = Net::HTTP.new(hostname) http.start http.started? # => true http.finish # => nil http.started? # => false
如果不在会话中,则引发 IOError
。
# File lib/net/http.rb, line 1708 def finish raise IOError, 'HTTP session not yet started' unless started? do_finish end
向服务器发送 GET 请求;返回一个 Net::HTTPResponse
子类的实例。
该请求基于从字符串 path
和初始头信息哈希 initheader
创建的 Net::HTTP::Get
对象。
如果给定代码块,则使用响应主体调用代码块
http = Net::HTTP.new(hostname) http.get('/todos/1') do |res| p res end # => #<Net::HTTPOK 200 OK readbody=true>
输出
"{\n \"userId\": 1,\n \"id\": 1,\n \"title\": \"delectus aut autem\",\n \"completed\": false\n}"
如果没有给定代码块,则只返回响应对象
http.get('/') # => #<Net::HTTPOK 200 OK readbody=true>
相关
-
Net::HTTP::Get
: HTTP 方法 GET 的请求类。 -
Net::HTTP.get
: 发送 GET 请求,返回响应主体。
# File lib/net/http.rb, line 1914 def get(path, initheader = nil, dest = nil, &block) # :yield: +body_segment+ res = nil request(Get.new(path, initheader)) {|r| r.read_body dest, &block res = r } res end
向服务器发送 HEAD 请求;返回一个 Net::HTTPResponse
子类的实例。
该请求基于从字符串 path
和初始头信息哈希 initheader
创建的 Net::HTTP::Head
对象
res = http.head('/todos/1') # => #<Net::HTTPOK 200 OK readbody=true> res.body # => nil res.to_hash.take(3) # => [["date", ["Wed, 15 Feb 2023 15:25:42 GMT"]], ["content-type", ["application/json; charset=utf-8"]], ["connection", ["close"]]]
# File lib/net/http.rb, line 1938 def head(path, initheader = nil) request(Head.new(path, initheader)) end
返回 self
的字符串表示形式
Net::HTTP.new(hostname).inspect # => "#<Net::HTTP jsonplaceholder.typicode.com:80 open=false>"
# File lib/net/http.rb, line 1135 def inspect "#<#{self.class} #{@address}:#{@port} open=#{started?}>" end
返回连接的 IP 地址。
如果会话尚未开始,则返回由 ipaddr=
设置的值,如果未设置,则返回 nil
。
http = Net::HTTP.new(hostname) http.ipaddr # => nil http.ipaddr = '172.67.155.76' http.ipaddr # => "172.67.155.76"
如果会话已开始,则返回套接字的 IP 地址。
http = Net::HTTP.new(hostname) http.start http.ipaddr # => "172.67.155.76" http.finish
# File lib/net/http.rb, line 1274 def ipaddr started? ? @socket.io.peeraddr[3] : @ipaddr end
设置连接的 IP 地址。
http = Net::HTTP.new(hostname) http.ipaddr # => nil http.ipaddr = '172.67.155.76' http.ipaddr # => "172.67.155.76"
如果会话已开始,则可能无法设置 IP 地址。
# File lib/net/http.rb, line 1286 def ipaddr=(addr) raise IOError, "ipaddr value changed, but session already started" if started? @ipaddr = addr end
向服务器发送 LOCK 请求;返回 Net::HTTPResponse
子类的实例。
该请求基于从字符串 path
、字符串 body
和初始标头哈希 initheader
创建的 Net::HTTP::Lock
对象。
data = '{"userId": 1, "id": 1, "title": "delectus aut autem", "completed": false}' http = Net::HTTP.new(hostname) http.lock('/todos/1', data)
# File lib/net/http.rb, line 2043 def lock(path, body, initheader = nil) request(Lock.new(path, initheader), body) end
设置在发生 Net::ReadTimeout、IOError
、EOFError
、Errno::ECONNRESET、Errno::ECONNABORTED、Errno::EPIPE、OpenSSL::SSL::SSLError
、Timeout::Error
时重试幂等请求的最大次数。初始值为 1。
参数 retries
必须是非负数值。
http = Net::HTTP.new(hostname) http.max_retries = 2 # => 2 http.max_retries # => 2
# File lib/net/http.rb, line 1320 def max_retries=(retries) retries = retries.to_int if retries < 0 raise ArgumentError, 'max_retries should be non-negative integer number' end @max_retries = retries end
向服务器发送 MKCOL 请求;返回 Net::HTTPResponse
子类的实例。
该请求基于从字符串 path
、字符串 body
和初始标头哈希 initheader
创建的 Net::HTTP::Mkcol
对象。
data = '{"userId": 1, "id": 1, "title": "delectus aut autem", "completed": false}' http.mkcol('/todos/1', data) http = Net::HTTP.new(hostname)
# File lib/net/http.rb, line 2137 def mkcol(path, body = nil, initheader = nil) request(Mkcol.new(path, initheader), body) end
向服务器发送 MOVE 请求;返回 Net::HTTPResponse
子类的实例。
该请求基于从字符串 path
和初始标头哈希 initheader
创建的 Net::HTTP::Move
对象。
http = Net::HTTP.new(hostname) http.move('/todos/1')
# File lib/net/http.rb, line 2110 def move(path, initheader = nil) request(Move.new(path, initheader)) end
向服务器发送 Options
请求;返回 Net::HTTPResponse
子类的实例。
请求基于从字符串path
和初始头信息哈希initheader
创建的Net::HTTP::Options
对象。
http = Net::HTTP.new(hostname) http.options('/')
# File lib/net/http.rb, line 2070 def options(path, initheader = nil) request(Options.new(path, initheader)) end
向服务器发送PATCH请求;返回Net::HTTPResponse
子类的实例。
请求基于从字符串path
、字符串data
和初始头信息哈希initheader
创建的Net::HTTP::Patch
对象。
如果给定代码块,则使用响应主体调用代码块
data = '{"userId": 1, "id": 1, "title": "delectus aut autem", "completed": false}' http = Net::HTTP.new(hostname) http.patch('/todos/1', data) do |res| p res end # => #<Net::HTTPOK 200 OK readbody=true>
输出
"{\n \"userId\": 1,\n \"id\": 1,\n \"title\": \"delectus aut autem\",\n \"completed\": false,\n \"{\\\"userId\\\": 1, \\\"id\\\": 1, \\\"title\\\": \\\"delectus aut autem\\\", \\\"completed\\\": false}\": \"\"\n}"
如果没有给定代码块,则只返回响应对象
http.patch('/todos/1', data) # => #<Net::HTTPCreated 201 Created readbody=true>
# File lib/net/http.rb, line 2001 def patch(path, data, initheader = nil, dest = nil, &block) # :yield: +body_segment+ send_entity(path, data, initheader, dest, Patch, &block) end
返回会话套接字对端的X509证书链(字符串数组),如果不存在则返回nil
。
# File lib/net/http.rb, line 1537 def peer_cert if not use_ssl? or not @socket return nil end @socket.io.peer_cert end
向服务器发送POST请求;返回Net::HTTPResponse
子类的实例。
请求基于从字符串path
、字符串data
和初始头信息哈希initheader
创建的Net::HTTP::Post
对象。
如果给定代码块,则使用响应主体调用代码块
data = '{"userId": 1, "id": 1, "title": "delectus aut autem", "completed": false}' http = Net::HTTP.new(hostname) http.post('/todos', data) do |res| p res end # => #<Net::HTTPCreated 201 Created readbody=true>
输出
"{\n \"{\\\"userId\\\": 1, \\\"id\\\": 1, \\\"title\\\": \\\"delectus aut autem\\\", \\\"completed\\\": false}\": \"\",\n \"id\": 201\n}"
如果没有给定代码块,则只返回响应对象
http.post('/todos', data) # => #<Net::HTTPCreated 201 Created readbody=true>
相关
-
Net::HTTP::Post
: HTTP方法POST的请求类。 -
Net::HTTP.post
: 发送POST请求,返回响应主体。
# File lib/net/http.rb, line 1972 def post(path, data, initheader = nil, dest = nil, &block) # :yield: +body_segment+ send_entity(path, data, initheader, dest, Post, &block) end
向服务器发送PROPFIND请求;返回Net::HTTPResponse
子类的实例。
请求基于从字符串path
、字符串body
和初始头信息哈希initheader
创建的Net::HTTP::Propfind
对象。
data = '{"userId": 1, "id": 1, "title": "delectus aut autem", "completed": false}' http = Net::HTTP.new(hostname) http.propfind('/todos/1', data)
# File lib/net/http.rb, line 2084 def propfind(path, body = nil, initheader = {'Depth' => '0'}) request(Propfind.new(path, initheader), body) end
向服务器发送PROPPATCH请求;返回Net::HTTPResponse
子类的实例。
该请求基于从字符串 `path`、字符串 `body` 和初始标头哈希 `initheader` 创建的 Net::HTTP::Proppatch
对象。
data = '{"userId": 1, "id": 1, "title": "delectus aut autem", "completed": false}' http = Net::HTTP.new(hostname) http.proppatch('/todos/1', data)
# File lib/net/http.rb, line 2029 def proppatch(path, body, initheader = nil) request(Proppatch.new(path, initheader), body) end
如果定义了代理服务器,则返回 `true`,否则返回 `false`;请参阅 代理服务器。
# File lib/net/http.rb, line 1785 def proxy? !!(@proxy_from_env ? proxy_uri : @proxy_address) end
如果定义了代理服务器,则返回代理服务器的地址,否则返回 `nil`;请参阅 代理服务器。
# File lib/net/http.rb, line 1807 def proxy_address if @proxy_from_env then proxy_uri&.hostname else @proxy_address end end
如果在环境中定义了代理服务器,则返回 `true`,否则返回 `false`;请参阅 代理服务器。
# File lib/net/http.rb, line 1792 def proxy_from_env? @proxy_from_env end
如果定义了代理服务器,则返回代理服务器的密码,否则返回 `nil`;请参阅 代理服务器。
# File lib/net/http.rb, line 1838 def proxy_pass if @proxy_from_env pass = proxy_uri&.password unescape(pass) if pass else @proxy_pass end end
如果定义了代理服务器,则返回代理服务器的端口号,否则返回 `nil`;请参阅 代理服务器。
# File lib/net/http.rb, line 1817 def proxy_port if @proxy_from_env then proxy_uri&.port else @proxy_port end end
如果定义了代理服务器,则返回代理服务器的用户名,否则返回 `nil`;请参阅 代理服务器。
# File lib/net/http.rb, line 1827 def proxy_user if @proxy_from_env user = proxy_uri&.user unescape(user) if user else @proxy_user end end
向服务器发送 PUT 请求;返回 Net::HTTPResponse
的子类的实例。
该请求基于从字符串 `path`、字符串 `data` 和初始标头哈希 `initheader` 创建的 Net::HTTP::Put
对象。
data = '{"userId": 1, "id": 1, "title": "delectus aut autem", "completed": false}' http = Net::HTTP.new(hostname) http.put('/todos/1', data) # => #<Net::HTTPOK 200 OK readbody=true>
# File lib/net/http.rb, line 2015 def put(path, data, initheader = nil) request(Put.new(path, initheader), data) end
设置 self
的读取超时时间(以秒为单位)为整数 sec
;初始值为 60。
参数 sec
必须是非负数值。
http = Net::HTTP.new(hostname) http.read_timeout # => 60 http.get('/todos/1') # => #<Net::HTTPOK 200 OK readbody=true> http.read_timeout = 0 http.get('/todos/1') # Raises Net::ReadTimeout.
# File lib/net/http.rb, line 1343 def read_timeout=(sec) @socket.read_timeout = sec if @socket @read_timeout = sec end
将给定的请求 req
发送到服务器;将响应格式化为 Net::HTTPResponse
对象。
给定的 req
必须是 Net::HTTPRequest 子类 的实例。仅在请求需要时才应提供参数 body
。
如果没有给出代码块,则返回响应对象。
http = Net::HTTP.new(hostname) req = Net::HTTP::Get.new('/todos/1') http.request(req) # => #<Net::HTTPOK 200 OK readbody=true> req = Net::HTTP::Post.new('/todos') http.request(req, 'xyzzy') # => #<Net::HTTPCreated 201 Created readbody=true>
如果给出代码块,则使用响应调用代码块并返回响应。
req = Net::HTTP::Get.new('/todos/1') http.request(req) do |res| p res end # => #<Net::HTTPOK 200 OK readbody=true>
输出
#<Net::HTTPOK 200 OK readbody=false>
# File lib/net/http.rb, line 2295 def request(req, body = nil, &block) # :yield: +response+ unless started? start { req['connection'] ||= 'close' return request(req, body, &block) } end if proxy_user() req.proxy_basic_auth proxy_user(), proxy_pass() unless use_ssl? end req.set_body_internal body res = transport_request(req, &block) if sspi_auth?(res) sspi_auth(req) res = transport_request(req, &block) end res end
向服务器发送 GET 请求;将响应格式化为 Net::HTTPResponse
对象。
该请求基于从字符串 path
和初始头信息哈希 initheader
创建的 Net::HTTP::Get
对象。
如果没有给出代码块,则返回响应对象。
http = Net::HTTP.new(hostname) http.request_get('/todos') # => #<Net::HTTPOK 200 OK readbody=true>
如果给出代码块,则使用响应对象调用代码块并返回响应对象。
http.request_get('/todos') do |res| p res end # => #<Net::HTTPOK 200 OK readbody=true>
输出
#<Net::HTTPOK 200 OK readbody=false>
# File lib/net/http.rb, line 2176 def request_get(path, initheader = nil, &block) # :yield: +response+ request(Get.new(path, initheader), &block) end
向服务器发送 HEAD 请求;返回一个 Net::HTTPResponse
子类的实例。
请求基于从字符串 path
和初始标头哈希 initheader
创建的 Net::HTTP::Head
对象。
http = Net::HTTP.new(hostname) http.head('/todos/1') # => #<Net::HTTPOK 200 OK readbody=true>
# File lib/net/http.rb, line 2189 def request_head(path, initheader = nil, &block) request(Head.new(path, initheader), &block) end
向服务器发送 POST 请求;将响应格式化为 Net::HTTPResponse
对象。
请求基于从字符串path
、字符串data
和初始头信息哈希initheader
创建的Net::HTTP::Post
对象。
如果没有给出代码块,则返回响应对象。
http = Net::HTTP.new(hostname) http.post('/todos', 'xyzzy') # => #<Net::HTTPCreated 201 Created readbody=true>
如果给出代码块,则使用响应主体调用代码块并返回响应对象。
http.post('/todos', 'xyzzy') do |res| p res end # => #<Net::HTTPCreated 201 Created readbody=true>
输出
"{\n \"xyzzy\": \"\",\n \"id\": 201\n}"
# File lib/net/http.rb, line 2216 def request_post(path, data, initheader = nil, &block) # :yield: +response+ request Post.new(path, initheader), data, &block end
设置用于响应主体的编码;返回编码。
给定的 value
可以是
-
Encoding
对象。 -
编码的名称。
-
编码名称的别名。
参见 Encoding
。
示例
http = Net::HTTP.new(hostname) http.response_body_encoding = Encoding::US_ASCII # => #<Encoding:US-ASCII> http.response_body_encoding = 'US-ASCII' # => "US-ASCII" http.response_body_encoding = 'ASCII' # => "ASCII"
# File lib/net/http.rb, line 1229 def response_body_encoding=(value) value = Encoding.find(value) if value.is_a?(String) @response_body_encoding = value end
向服务器发送 HTTP 请求;返回 Net::HTTPResponse
子类的实例。
该请求基于从字符串 path
、字符串 data
和初始标头哈希 header
创建的 Net::HTTPRequest
对象。该对象是 Net::HTTPRequest 子类 的实例,对应于给定的大写字符串 name
,该字符串必须是 HTTP 请求方法 或 WebDAV 请求方法。
示例
http = Net::HTTP.new(hostname) http.send_request('GET', '/todos/1') # => #<Net::HTTPOK 200 OK readbody=true> http.send_request('POST', '/todos', 'xyzzy') # => #<Net::HTTPCreated 201 Created readbody=true>
# File lib/net/http.rb, line 2259 def send_request(name, path, data = nil, header = nil) has_response_body = name != 'HEAD' r = HTTPGenericRequest.new(name,(data ? true : false),has_response_body,path,header) request r, data end
警告 此方法会打开一个严重的安全性漏洞。切勿在生产代码中使用此方法。
设置调试的输出流
http = Net::HTTP.new(hostname) File.open('t.tmp', 'w') do |file| http.set_debug_output(file) http.start http.get('/nosuch/1') http.finish end puts File.read('t.tmp')
输出
opening connection to jsonplaceholder.typicode.com:80... opened <- "GET /nosuch/1 HTTP/1.1\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nHost: jsonplaceholder.typicode.com\r\n\r\n" -> "HTTP/1.1 404 Not Found\r\n" -> "Date: Mon, 12 Dec 2022 21:14:11 GMT\r\n" -> "Content-Type: application/json; charset=utf-8\r\n" -> "Content-Length: 2\r\n" -> "Connection: keep-alive\r\n" -> "X-Powered-By: Express\r\n" -> "X-Ratelimit-Limit: 1000\r\n" -> "X-Ratelimit-Remaining: 999\r\n" -> "X-Ratelimit-Reset: 1670879660\r\n" -> "Vary: Origin, Accept-Encoding\r\n" -> "Access-Control-Allow-Credentials: true\r\n" -> "Cache-Control: max-age=43200\r\n" -> "Pragma: no-cache\r\n" -> "Expires: -1\r\n" -> "X-Content-Type-Options: nosniff\r\n" -> "Etag: W/\"2-vyGp6PvFo4RvsFtPoIWeCReyIC8\"\r\n" -> "Via: 1.1 vegur\r\n" -> "CF-Cache-Status: MISS\r\n" -> "Server-Timing: cf-q-config;dur=1.3000000762986e-05\r\n" -> "Report-To: {\"endpoints\":[{\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v3?s=yOr40jo%2BwS1KHzhTlVpl54beJ5Wx2FcG4gGV0XVrh3X9OlR5q4drUn2dkt5DGO4GDcE%2BVXT7CNgJvGs%2BZleIyMu8CLieFiDIvOviOY3EhHg94m0ZNZgrEdpKD0S85S507l1vsEwEHkoTm%2Ff19SiO\"}],\"group\":\"cf-nel\",\"max_age\":604800}\r\n" -> "NEL: {\"success_fraction\":0,\"report_to\":\"cf-nel\",\"max_age\":604800}\r\n" -> "Server: cloudflare\r\n" -> "CF-RAY: 778977dc484ce591-DFW\r\n" -> "alt-svc: h3=\":443\"; ma=86400, h3-29=\":443\"; ma=86400\r\n" -> "\r\n" reading 2 bytes... -> "{}" read 2 bytes Conn keep-alive
# File lib/net/http.rb, line 1188 def set_debug_output(output) warn 'Net::HTTP#set_debug_output called after HTTP started', uplevel: 1 if started? @debug_output = output end
启动 HTTP 会话。
没有块,返回 self
http = Net::HTTP.new(hostname) # => #<Net::HTTP jsonplaceholder.typicode.com:80 open=false> http.start # => #<Net::HTTP jsonplaceholder.typicode.com:80 open=true> http.started? # => true http.finish
有块,用 self
调用块,在块退出时结束会话,并返回块的值
http.start do |http| http end # => #<Net::HTTP jsonplaceholder.typicode.com:80 open=false> http.started? # => false
# File lib/net/http.rb, line 1565 def start # :yield: http raise IOError, 'HTTP session already opened' if @started if block_given? begin do_start return yield(self) ensure do_finish end end do_start self end
如果 HTTP 会话已启动,则返回 true
http = Net::HTTP.new(hostname) http.started? # => false http.start http.started? # => true http.finish # => nil http.started? # => false Net::HTTP.start(hostname) do |http| http.started? end # => true http.started? # => false
# File lib/net/http.rb, line 1413 def started? @started end
向服务器发送 TRACE 请求;返回 Net::HTTPResponse
子类的实例。
该请求基于从字符串 path
和初始标头哈希 initheader
创建的 Net::HTTP::Trace
对象。
http = Net::HTTP.new(hostname) http.trace('/todos/1')
# File lib/net/http.rb, line 2150 def trace(path, initheader = nil) request(Trace.new(path, initheader)) end
向服务器发送 UNLOCK 请求;返回 Net::HTTPResponse
子类的实例。
该请求基于从字符串path
、字符串body
和初始头哈希initheader
创建的Net::HTTP::Unlock
对象。
data = '{"userId": 1, "id": 1, "title": "delectus aut autem", "completed": false}' http = Net::HTTP.new(hostname) http.unlock('/todos/1', data)
# File lib/net/http.rb, line 2057 def unlock(path, body, initheader = nil) request(Unlock.new(path, initheader), body) end
设置新的会话是否使用传输层安全
如果尝试在会话期间更改,则会引发IOError
。
如果端口不是 HTTPS 端口,则会引发OpenSSL::SSL::SSLError
。
# File lib/net/http.rb, line 1435 def use_ssl=(flag) flag = flag ? true : false if started? and @use_ssl != flag raise IOError, "use_ssl value changed, but session already started" end @use_ssl = flag end
如果self
使用 SSL,则返回true
,否则返回false
。请参阅Net::HTTP#use_ssl=
。
# File lib/net/http.rb, line 1425 def use_ssl? @use_ssl end
将self
的写入超时时间(以秒为单位)设置为整数sec
;初始值为 60。
参数 sec
必须是非负数值。
_uri = uri.dup _uri.path = '/posts' body = 'bar' * 200000 data = <<EOF {"title": "foo", "body": "#{body}", "userId": "1"} EOF headers = {'content-type': 'application/json'} http = Net::HTTP.new(hostname) http.write_timeout # => 60 http.post(_uri.path, data, headers) # => #<Net::HTTPCreated 201 Created readbody=true> http.write_timeout = 0 http.post(_uri.path, data, headers) # Raises Net::WriteTimeout.
# File lib/net/http.rb, line 1367 def write_timeout=(sec) @socket.write_timeout = sec if @socket @write_timeout = sec end
私有实例方法
实用程序
# File lib/net/http.rb, line 2464 def addr_port addr = address addr = "[#{addr}]" if addr.include?(":") default_port = use_ssl? ? HTTP.https_default_port : HTTP.http_default_port default_port == port ? addr : "#{addr}:#{port}" end
# File lib/net/http.rb, line 2381 def begin_transport(req) if @socket.closed? connect elsif @last_communicated if @last_communicated + @keep_alive_timeout < Process.clock_gettime(Process::CLOCK_MONOTONIC) debug 'Conn close because of keep_alive_timeout' @socket.close connect elsif @socket.io.to_io.wait_readable(0) && @socket.eof? debug "Conn close because of EOF" @socket.close connect end end if not req.response_body_permitted? and @close_on_empty_response req['connection'] ||= 'close' end req.update_uri address, port, use_ssl? req['host'] ||= addr_port() end
# File lib/net/http.rb, line 1585 def connect if use_ssl? # reference early to load OpenSSL before connecting, # as OpenSSL may take time to load. @ssl_context = OpenSSL::SSL::SSLContext.new end if proxy? then conn_addr = proxy_address conn_port = proxy_port else conn_addr = conn_address conn_port = port end debug "opening connection to #{conn_addr}:#{conn_port}..." s = Timeout.timeout(@open_timeout, Net::OpenTimeout) { begin TCPSocket.open(conn_addr, conn_port, @local_host, @local_port) rescue => e raise e, "Failed to open TCP connection to " + "#{conn_addr}:#{conn_port} (#{e.message})" end } s.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1) debug "opened" if use_ssl? if proxy? plain_sock = BufferedIO.new(s, read_timeout: @read_timeout, write_timeout: @write_timeout, continue_timeout: @continue_timeout, debug_output: @debug_output) buf = +"CONNECT #{conn_address}:#{@port} HTTP/#{HTTPVersion}\r\n" \ "Host: #{@address}:#{@port}\r\n" if proxy_user credential = ["#{proxy_user}:#{proxy_pass}"].pack('m0') buf << "Proxy-Authorization: Basic #{credential}\r\n" end buf << "\r\n" plain_sock.write(buf) HTTPResponse.read_new(plain_sock).value # assuming nothing left in buffers after successful CONNECT response end ssl_parameters = Hash.new iv_list = instance_variables SSL_IVNAMES.each_with_index do |ivname, i| if iv_list.include?(ivname) value = instance_variable_get(ivname) unless value.nil? ssl_parameters[SSL_ATTRIBUTES[i]] = value end end end @ssl_context.set_params(ssl_parameters) unless @ssl_context.session_cache_mode.nil? # a dummy method on JRuby @ssl_context.session_cache_mode = OpenSSL::SSL::SSLContext::SESSION_CACHE_CLIENT | OpenSSL::SSL::SSLContext::SESSION_CACHE_NO_INTERNAL_STORE end if @ssl_context.respond_to?(:session_new_cb) # not implemented under JRuby @ssl_context.session_new_cb = proc {|sock, sess| @ssl_session = sess } end # Still do the post_connection_check below even if connecting # to IP address verify_hostname = @ssl_context.verify_hostname # Server Name Indication (SNI) RFC 3546/6066 case @address when Resolv::IPv4::Regex, Resolv::IPv6::Regex # don't set SNI, as IP addresses in SNI is not valid # per RFC 6066, section 3. # Avoid openssl warning @ssl_context.verify_hostname = false else ssl_host_address = @address end debug "starting SSL for #{conn_addr}:#{conn_port}..." s = OpenSSL::SSL::SSLSocket.new(s, @ssl_context) s.sync_close = true s.hostname = ssl_host_address if s.respond_to?(:hostname=) && ssl_host_address if @ssl_session and Process.clock_gettime(Process::CLOCK_REALTIME) < @ssl_session.time.to_f + @ssl_session.timeout s.session = @ssl_session end ssl_socket_connect(s, @open_timeout) if (@ssl_context.verify_mode != OpenSSL::SSL::VERIFY_NONE) && verify_hostname s.post_connection_check(@address) end debug "SSL established, protocol: #{s.ssl_version}, cipher: #{s.cipher[0]}" end @socket = BufferedIO.new(s, read_timeout: @read_timeout, write_timeout: @write_timeout, continue_timeout: @continue_timeout, debug_output: @debug_output) @last_communicated = nil on_connect rescue => exception if s debug "Conn close because of connect error #{exception}" s.close end raise end
向调试输出添加消息
# File lib/net/http.rb, line 2472 def debug(msg) return unless @debug_output @debug_output << msg @debug_output << "\n" end
# File lib/net/http.rb, line 1713 def do_finish @started = false @socket.close if @socket @socket = nil end
# File lib/net/http.rb, line 1579 def do_start connect @started = true end
# File lib/net/http.rb, line 1867 def edit_path(path) if proxy? if path.start_with?("ftp://") || use_ssl? path else "http://#{addr_port}#{path}" end else path end end
# File lib/net/http.rb, line 2404 def end_transport(req, res) @curr_http_version = res.http_version @last_communicated = nil if @socket.closed? debug 'Conn socket closed' elsif not res.body and @close_on_empty_response debug 'Conn close' @socket.close elsif keep_alive?(req, res) debug 'Conn keep-alive' @last_communicated = Process.clock_gettime(Process::CLOCK_MONOTONIC) else debug 'Conn close' @socket.close end end
# File lib/net/http.rb, line 2421 def keep_alive?(req, res) return false if req.connection_close? if @curr_http_version <= '1.0' res.connection_keep_alive? else # HTTP/1.1 or later not res.connection_close? end end
# File lib/net/http.rb, line 1695 def on_connect end
执行使用表示形式的请求并返回其主体。
# File lib/net/http.rb, line 2318 def send_entity(path, data, initheader, dest, type, &block) res = nil request(type.new(path, initheader), data) {|r| r.read_body dest, &block res = r } res end
# File lib/net/http.rb, line 2445 def sspi_auth(req) n = Win32::SSPI::NegotiateAuth.new req["Proxy-Authorization"] = "Negotiate #{n.get_initial_token}" # Some versions of ISA will close the connection if this isn't present. req["Connection"] = "Keep-Alive" req["Proxy-Connection"] = "Keep-Alive" res = transport_request(req) authphrase = res["Proxy-Authenticate"] or return res req["Proxy-Authorization"] = "Negotiate #{n.complete_authentication(authphrase)}" rescue => err raise HTTPAuthenticationError.new('HTTP authentication failed', err) end
# File lib/net/http.rb, line 2430 def sspi_auth?(res) return false unless @sspi_enabled if res.kind_of?(HTTPProxyAuthenticationRequired) and proxy? and res["Proxy-Authenticate"].include?("Negotiate") begin require 'win32/sspi' true rescue LoadError false end else false end end
# File lib/net/http.rb, line 2329 def transport_request(req) count = 0 begin begin_transport req res = catch(:response) { begin req.exec @socket, @curr_http_version, edit_path(req.path) rescue Errno::EPIPE # Failure when writing full request, but we can probably # still read the received response. end begin res = HTTPResponse.read_new(@socket) res.decode_content = req.decode_content res.body_encoding = @response_body_encoding res.ignore_eof = @ignore_eof end while res.kind_of?(HTTPInformation) res.uri = req.uri res } res.reading_body(@socket, req.response_body_permitted?) { yield res if block_given? } rescue Net::OpenTimeout raise rescue Net::ReadTimeout, IOError, EOFError, Errno::ECONNRESET, Errno::ECONNABORTED, Errno::EPIPE, Errno::ETIMEDOUT, # avoid a dependency on OpenSSL defined?(OpenSSL::SSL) ? OpenSSL::SSL::SSLError : IOError, Timeout::Error => exception if count < max_retries && IDEMPOTENT_METHODS_.include?(req.method) count += 1 @socket.close if @socket debug "Conn close because of error #{exception}, and retry" retry end debug "Conn close because of error #{exception}" @socket.close if @socket raise end end_transport req, res res rescue => exception debug "Conn close because of error #{exception}" @socket.close if @socket raise exception end
# File lib/net/http.rb, line 1852 def unescape(value) require 'cgi/util' CGI.unescape(value) end