类 Net::HTTPGenericRequest
HTTPGenericRequest 是 Net::HTTPRequest
类的父类。
不要直接使用它;而是使用 Net::HTTPRequest
的子类。
关于示例¶ ↑
此处的示例假设已要求 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'
属性
body[R]
返回请求的字符串主体,如果没有则返回 nil
req = Net::HTTP::Post.new(uri) req.body # => nil req.body = '{"title": "foo","body": "bar","userId": 1}' req.body # => "{\"title\": \"foo\",\"body\": \"bar\",\"userId\": 1}"
body_stream[R]
返回请求的主体流对象,如果没有则返回 nil
req = Net::HTTP::Post.new(uri) # => #<Net::HTTP::Post POST> req.body_stream # => nil require 'stringio' req.body_stream = StringIO.new('xyzzy') # => #<StringIO:0x0000027d1e5affa8> req.body_stream # => #<StringIO:0x0000027d1e5affa8>
decode_content[R]
如果请求的标头 'Accept-Encoding'
已手动设置或删除(表示用户打算处理响应中的编码),则返回 false
,否则返回 true
req = Net::HTTP::Get.new(uri) # => #<Net::HTTP::Get GET> req['Accept-Encoding'] # => "gzip;q=1.0,deflate;q=0.6,identity;q=0.3" req.decode_content # => true req['Accept-Encoding'] = 'foo' req.decode_content # => false req.delete('Accept-Encoding') req.decode_content # => false
method[R]
返回请求的字符串方法名称
Net::HTTP::Get.new(uri).method # => "GET" Net::HTTP::Post.new(uri).method # => "POST"
path[R]
返回请求的字符串路径
Net::HTTP::Get.new(uri).path # => "/" Net::HTTP::Post.new('example.com').path # => "example.com"
uri[R]
返回请求的 URI
对象,如果不存在则返回 nil
Net::HTTP::Get.new(uri).uri # => #<URI::HTTPS https://jsonplaceholder.typicode.com/> Net::HTTP::Get.new('example.com').uri # => nil
公共实例方法
body=(str) 点击切换源代码
设置请求的正文
req = Net::HTTP::Post.new(uri) req.body # => nil req.body = '{"title": "foo","body": "bar","userId": 1}' req.body # => "{\"title\": \"foo\",\"body\": \"bar\",\"userId\": 1}"
# File lib/net/http/generic_request.rb, line 154 def body=(str) @body = str @body_stream = nil @body_data = nil str end
body_stream=(input) 点击切换源代码
设置请求的正文流
req = Net::HTTP::Post.new(uri) # => #<Net::HTTP::Post POST> req.body_stream # => nil require 'stringio' req.body_stream = StringIO.new('xyzzy') # => #<StringIO:0x0000027d1e5affa8> req.body_stream # => #<StringIO:0x0000027d1e5affa8>
# File lib/net/http/generic_request.rb, line 179 def body_stream=(input) @body = nil @body_stream = input @body_data = nil input end
inspect() 点击切换源代码
返回请求的字符串表示形式
Net::HTTP::Post.new(uri).inspect # => "#<Net::HTTP::Post POST>"
# File lib/net/http/generic_request.rb, line 101 def inspect "\#<#{self.class} #{@method}>" end
request_body_permitted?() 点击切换源代码
返回请求是否可以有正文
Net::HTTP::Post.new(uri).request_body_permitted? # => true Net::HTTP::Get.new(uri).request_body_permitted? # => false
# File lib/net/http/generic_request.rb, line 120 def request_body_permitted? @request_has_body end
response_body_permitted?() 点击切换源代码
返回响应是否可以有正文
Net::HTTP::Post.new(uri).response_body_permitted? # => true Net::HTTP::Head.new(uri).response_body_permitted? # => false
# File lib/net/http/generic_request.rb, line 129 def response_body_permitted? @response_has_body end
私有实例方法
encode_multipart_form_data(out, params, opt) 点击切换源代码
# File lib/net/http/generic_request.rb, line 312 def encode_multipart_form_data(out, params, opt) charset = opt[:charset] boundary = opt[:boundary] require 'securerandom' unless defined?(SecureRandom) boundary ||= SecureRandom.urlsafe_base64(40) chunked_p = chunked? buf = +'' params.each do |key, value, h={}| key = quote_string(key, charset) filename = h.key?(:filename) ? h[:filename] : value.respond_to?(:to_path) ? File.basename(value.to_path) : nil buf << "--#{boundary}\r\n" if filename filename = quote_string(filename, charset) type = h[:content_type] || 'application/octet-stream' buf << "Content-Disposition: form-data; " \ "name=\"#{key}\"; filename=\"#{filename}\"\r\n" \ "Content-Type: #{type}\r\n\r\n" if !out.respond_to?(:write) || !value.respond_to?(:read) # if +out+ is not an IO or +value+ is not an IO buf << (value.respond_to?(:read) ? value.read : value) elsif value.respond_to?(:size) && chunked_p # if +out+ is an IO and +value+ is a File, use IO.copy_stream flush_buffer(out, buf, chunked_p) out << "%x\r\n" % value.size if chunked_p IO.copy_stream(value, out) out << "\r\n" if chunked_p else # +out+ is an IO, and +value+ is not a File but an IO flush_buffer(out, buf, chunked_p) 1 while flush_buffer(out, value.read(4096), chunked_p) end else # non-file field: # HTML5 says, "The parts of the generated multipart/form-data # resource that correspond to non-file fields must not have a # Content-Type header specified." buf << "Content-Disposition: form-data; name=\"#{key}\"\r\n\r\n" buf << (value.respond_to?(:read) ? value.read : value) end buf << "\r\n" end buf << "--#{boundary}--\r\n" flush_buffer(out, buf, chunked_p) out << "0\r\n\r\n" if chunked_p end
flush_buffer(out, buf, chunked_p) 点击切换源代码
# File lib/net/http/generic_request.rb, line 368 def flush_buffer(out, buf, chunked_p) return unless buf out << "%x\r\n"%buf.bytesize if chunked_p out << buf out << "\r\n" if chunked_p buf.clear end
quote_string(str, charset) 点击切换源代码
# File lib/net/http/generic_request.rb, line 363 def quote_string(str, charset) str = str.encode(charset, fallback:->(c){'&#%d;'%c.encode("UTF-8").ord}) if charset str.gsub(/[\\"]/, '\\\\\&') end
send_request_with_body(sock, ver, path, body) 点击切换源代码
# File lib/net/http/generic_request.rb, line 260 def send_request_with_body(sock, ver, path, body) self.content_length = body.bytesize delete 'Transfer-Encoding' supply_default_content_type write_header sock, ver, path wait_for_continue sock, ver if sock.continue_timeout sock.write body end
send_request_with_body_data(sock, ver, path, params) 点击切换源代码
# File lib/net/http/generic_request.rb, line 286 def send_request_with_body_data(sock, ver, path, params) if /\Amultipart\/form-data\z/i !~ self.content_type self.content_type = 'application/x-www-form-urlencoded' return send_request_with_body(sock, ver, path, URI.encode_www_form(params)) end opt = @form_option.dup require 'securerandom' unless defined?(SecureRandom) opt[:boundary] ||= SecureRandom.urlsafe_base64(40) self.set_content_type(self.content_type, boundary: opt[:boundary]) if chunked? write_header sock, ver, path encode_multipart_form_data(sock, params, opt) else require 'tempfile' file = Tempfile.new('multipart') file.binmode encode_multipart_form_data(file, params, opt) file.rewind self.content_length = file.size write_header sock, ver, path IO.copy_stream(file, sock) file.close(true) end end
send_request_with_body_stream(sock, ver, path, f) 点击切换源代码
# File lib/net/http/generic_request.rb, line 269 def send_request_with_body_stream(sock, ver, path, f) unless content_length() or chunked? raise ArgumentError, "Content-Length not given and Transfer-Encoding is not `chunked'" end supply_default_content_type write_header sock, ver, path wait_for_continue sock, ver if sock.continue_timeout if chunked? chunker = Chunker.new(sock) IO.copy_stream(f, chunker) chunker.finish else IO.copy_stream(f, sock) end end
supply_default_content_type() 点击切换源代码
# File lib/net/http/generic_request.rb, line 376 def supply_default_content_type return if content_type() warn 'net/http: Content-Type did not set; using application/x-www-form-urlencoded', uplevel: 1 if $VERBOSE set_content_type 'application/x-www-form-urlencoded' end
wait_for_continue(sock, ver) 点击切换源代码
等待最多持续时间,以获取来自服务器的响应,前提是我们正在使用 HTTP 1.1 并且正在期待 100-continue 响应。
# File lib/net/http/generic_request.rb, line 386 def wait_for_continue(sock, ver) if ver >= '1.1' and @header['expect'] and @header['expect'].include?('100-continue') if sock.io.to_io.wait_readable(sock.continue_timeout) res = Net::HTTPResponse.read_new(sock) unless res.kind_of?(Net::HTTPContinue) res.decode_content = @decode_content throw :response, res end end end end
write_header(sock, ver, path) 点击切换源代码
# File lib/net/http/generic_request.rb, line 399 def write_header(sock, ver, path) reqline = "#{@method} #{path} HTTP/#{ver}" if /[\r\n]/ =~ reqline raise ArgumentError, "A Request-Line must not contain CR or LF" end buf = +'' buf << reqline << "\r\n" each_capitalized do |k,v| buf << "#{k}: #{v}\r\n" end buf << "\r\n" sock.write buf end