類別 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)
片段¶ ↑
URI 片段 在 Net::HTTP 中沒有作用;無論是否包含片段,都會傳回相同的資料。
要求標頭¶ ↑
要求標頭可用於傳遞額外的資訊給主機,類似於在方法呼叫中傳遞的參數;每個標頭都是一個名稱/值對。
每個將要求傳送至主機的 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 的會話¶ ↑
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¶ ↑
HTTPS 是透過 Net::HTTP#use_ssl=
為 HTTP 連線啟用
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
會將指定的 host 設定為其代理伺服器
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"
這會要求伺服器將回應主體壓縮編碼(如果有的話);伺服器不需要這麼做。
如果回應有標頭 '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
-
#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_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: 傳回會話 Socket 對等方的 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
如果自己是 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
。 -
對於定義 proxy 的引數
p_addr
到p_pass
,請參閱 Proxy Server。 -
對於引數
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"
如果會話已開始,則傳回 socket 的 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
傳回會話 socket 對等方的 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
可能為
-
編碼
物件。 -
編碼名稱。
-
編碼名稱的別名。
請參閱 編碼
。
範例
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
私有實例方法
utils
# 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