如何在 ruby 中使用 httpclient 发送多部分流请求
How to send a multipart streaming request using httpclient in ruby
我正在尝试使用 Ruby 的 HTTPClient 进行多部分流式传输 post。我遇到了两个问题。
问题 1:
首先,如果我尝试通过文档中描述的方式执行正常的 post ;我 return 通过 httpbin.org
我看到了这种情况:
代码
File.open(path_to_my_file) do |file|
body = [{ 'Content-Type' => 'application/atom+xml; charset=UTF-8',
:content => '<entry>...</entry>' },
{ 'Content-Type' => 'video/mp4',
'Content-Transfer-Encoding' => 'binary',
:content => file }]
res = @http_client.post('http://httpbin.org/post', body: body)
response = res
puts res.body
结果
{
"args": {},
"data": "",
"files": {},
"form": {
"{\"Content-Type\"=>\"application/atom+xml; charset=UTF-8\", :content=>\"<entry>...</entry>\"}": "",
"{\"Content-Type\"=>\"video/mp4\", \"Content-Transfer-Encoding\"=>\"binary\", :content=>#<File:{{path_to_file}}>}": ""
},
"headers": {
"Accept": "*/*",
"Content-Length": "322",
"Content-Type": "application/x-www-form-urlencoded",
"Date": "Mon, 20 May 2019 06:43:17 GMT",
"Host": "httpbin.org",
"User-Agent": "HTTPClient/1.0 (2.8.3, ruby 2.6.0 (2018-12-25))"
},
"json": null,
"origin": "IP, IP",
"url": "https://httpbin.org/post"
}
如您所见,我看不到文件的内容,只能看到包含文件URI的标识符;因此,我不知道如何修复它以便我可以看到和 return 内容。据我所知,它似乎试图将文件 object 视为一个字符串,这当然不是我想要的。
问题2:
每当我动态创建 body 时,即;使用我的代码中设置的 object 动态创建 hash-array,我尝试异步发送它(我相信这是在 Ruby 的 HTTPClient 中让它流式传输的正确方法,尽管我我不完全确定)
它将整个 body 作为数据发送,不再作为表单或 headers.
代码
request_body = []
body.files.each do |k, v|
request_body.push( { 'Content-Type' => v.content_type, :content => v.content })
end
body.values.each { |k, v| request_body << { k.to_sym => v }}
#This creates the array correctly, although I just wanted to show how it was generated
connection = @http_client.send(method + '_async', uri, body: request_body, header: headers)
response = connection.pop
# Starts reading result here
回应
"args": {},
"data": "%7B%22Content-Type%22%3D%3E%22video%2Fmp4%22%2C+%3Acontent%3D%3E%23%3CFile%3A%2Fhome%2Fuser%2Ffiles%2file.mp4%3E%7D=&%7B%3Avalue%3D%3E%22hello+world%22%7D=",
"files": {},
"form": {},
"headers": {
"Accept": "*/*",
"Content-Length": "247",
"Content-Type": "application/json",
"Date": "Mon, 20 May 2019 06:44:11 GMT",
"Host": "httpbin.org",
"User-Agent": "HTTPClient/1.0 (2.8.3, ruby 2.6.0 (2018-12-25))",
"ApplicationIdentifier": "identifier"
},
"json": null,
"origin": "IP, IP",
"url": "https://httpbin.org/post"
}
如您所见,它将所有内容都放入数据中,老实说,我不知道如何让它以形式而不是数据形式发送带有 body 的 post。我将文件作为文件 object 发送到这里。
我曾尝试将其作为普通 post 而不是 post_async 发送,但它似乎不起作用。
有没有人以前遇到过这些问题并且知道我应该如何解决这些问题? (或者你能看看我哪里出错了,这样我至少可以尝试更进一步)
提前致谢
关于您的第一个问题,文档似乎不正确。我进行了一些测试,内容类型似乎是 application/x-www-form-urlencoded。您需要明确设置内容类型:
body: body, header: {'Content-Type': 'multipart/form-data; boundary=ABC'}
但这还不够。您还需要手动设置内容处置。例如:
body = [{ 'Content-Type' => 'application/atom+xml; charset=UTF-8',
'Content-Disposition' => 'form-data; name="name1"',
:content => '<entry>...</entry>' },
{ 'Content-Type' => 'video/mp4',
'Content-Disposition' => 'form-data; name="file"; filename="myfile.pdf"',
'Content-Transfer-Encoding' => 'binary',
:content => file }]
有了这个,httpbin 报告了一个文件和一个表单参数。
你的第二个问题与此有关。您的文件和值都需要设置内容处置。例如(又快又脏,风格可能会更好):
files.each do |k, v|
request_body << { 'Content-Type' => v.content_type, :content => v.content, 'Content-Disposition' => 'form-data; name="' + k + '"; filename="' + v.filename + '"' }
end
values.each { |k, v| request_body << { :content => v, 'Content-Disposition' => 'form-data; name="' + k + '"' }}
请注意,您应该对名称或文件名中的任何 " 进行转义。
我正在尝试使用 Ruby 的 HTTPClient 进行多部分流式传输 post。我遇到了两个问题。
问题 1: 首先,如果我尝试通过文档中描述的方式执行正常的 post ;我 return 通过 httpbin.org 我看到了这种情况:
代码
File.open(path_to_my_file) do |file|
body = [{ 'Content-Type' => 'application/atom+xml; charset=UTF-8',
:content => '<entry>...</entry>' },
{ 'Content-Type' => 'video/mp4',
'Content-Transfer-Encoding' => 'binary',
:content => file }]
res = @http_client.post('http://httpbin.org/post', body: body)
response = res
puts res.body
结果
{
"args": {},
"data": "",
"files": {},
"form": {
"{\"Content-Type\"=>\"application/atom+xml; charset=UTF-8\", :content=>\"<entry>...</entry>\"}": "",
"{\"Content-Type\"=>\"video/mp4\", \"Content-Transfer-Encoding\"=>\"binary\", :content=>#<File:{{path_to_file}}>}": ""
},
"headers": {
"Accept": "*/*",
"Content-Length": "322",
"Content-Type": "application/x-www-form-urlencoded",
"Date": "Mon, 20 May 2019 06:43:17 GMT",
"Host": "httpbin.org",
"User-Agent": "HTTPClient/1.0 (2.8.3, ruby 2.6.0 (2018-12-25))"
},
"json": null,
"origin": "IP, IP",
"url": "https://httpbin.org/post"
}
如您所见,我看不到文件的内容,只能看到包含文件URI的标识符;因此,我不知道如何修复它以便我可以看到和 return 内容。据我所知,它似乎试图将文件 object 视为一个字符串,这当然不是我想要的。
问题2: 每当我动态创建 body 时,即;使用我的代码中设置的 object 动态创建 hash-array,我尝试异步发送它(我相信这是在 Ruby 的 HTTPClient 中让它流式传输的正确方法,尽管我我不完全确定) 它将整个 body 作为数据发送,不再作为表单或 headers.
代码
request_body = []
body.files.each do |k, v|
request_body.push( { 'Content-Type' => v.content_type, :content => v.content })
end
body.values.each { |k, v| request_body << { k.to_sym => v }}
#This creates the array correctly, although I just wanted to show how it was generated
connection = @http_client.send(method + '_async', uri, body: request_body, header: headers)
response = connection.pop
# Starts reading result here
回应
"args": {},
"data": "%7B%22Content-Type%22%3D%3E%22video%2Fmp4%22%2C+%3Acontent%3D%3E%23%3CFile%3A%2Fhome%2Fuser%2Ffiles%2file.mp4%3E%7D=&%7B%3Avalue%3D%3E%22hello+world%22%7D=",
"files": {},
"form": {},
"headers": {
"Accept": "*/*",
"Content-Length": "247",
"Content-Type": "application/json",
"Date": "Mon, 20 May 2019 06:44:11 GMT",
"Host": "httpbin.org",
"User-Agent": "HTTPClient/1.0 (2.8.3, ruby 2.6.0 (2018-12-25))",
"ApplicationIdentifier": "identifier"
},
"json": null,
"origin": "IP, IP",
"url": "https://httpbin.org/post"
}
如您所见,它将所有内容都放入数据中,老实说,我不知道如何让它以形式而不是数据形式发送带有 body 的 post。我将文件作为文件 object 发送到这里。 我曾尝试将其作为普通 post 而不是 post_async 发送,但它似乎不起作用。
有没有人以前遇到过这些问题并且知道我应该如何解决这些问题? (或者你能看看我哪里出错了,这样我至少可以尝试更进一步)
提前致谢
关于您的第一个问题,文档似乎不正确。我进行了一些测试,内容类型似乎是 application/x-www-form-urlencoded。您需要明确设置内容类型:
body: body, header: {'Content-Type': 'multipart/form-data; boundary=ABC'}
但这还不够。您还需要手动设置内容处置。例如:
body = [{ 'Content-Type' => 'application/atom+xml; charset=UTF-8',
'Content-Disposition' => 'form-data; name="name1"',
:content => '<entry>...</entry>' },
{ 'Content-Type' => 'video/mp4',
'Content-Disposition' => 'form-data; name="file"; filename="myfile.pdf"',
'Content-Transfer-Encoding' => 'binary',
:content => file }]
有了这个,httpbin 报告了一个文件和一个表单参数。
你的第二个问题与此有关。您的文件和值都需要设置内容处置。例如(又快又脏,风格可能会更好):
files.each do |k, v|
request_body << { 'Content-Type' => v.content_type, :content => v.content, 'Content-Disposition' => 'form-data; name="' + k + '"; filename="' + v.filename + '"' }
end
values.each { |k, v| request_body << { :content => v, 'Content-Disposition' => 'form-data; name="' + k + '"' }}
请注意,您应该对名称或文件名中的任何 " 进行转义。