带有 json 和文件数据的 Faraday 多部分请求
Faraday multipart request with json & file data
当尝试 POST 多部分数据(文件 & json)与 Faraday gem 时,远程服务器无法识别 json 数据参数并且失败并出现验证错误它是必需的参数。
connection = Faraday.new(url: "#{uri.scheme}://#{uri.host}:#{uri.port}") do |faraday|
faraday.request :multipart
faraday.request :url_encoded
faraday.adapter :net_http
end
request_data = { file: Faraday::UploadIO.new('somefile.png', 'image/png'), jsonBody: JSON.dump({ id: 'foo', name: 'bar' }) }
response = connection.post(uri.request_uri) do |request|
request = Ff::Api::RequestHeaders.set(request, self.api_options)
request.headers['content-type'] = 'multipart/form-data; boundary=-----------RubyMultipartPost'
request.body = request_data
end
工作 CURL 请求:
curl -v -H 'Authorization: bearer 7d70fb31-0eb9-4846-9ea8-933dfb69d8f1' \
-H 'Accept: application/xml,application/xhtml+xml,application/json,text/html,text/plain' \
-H 'Content-Type: multipart/form-data' \
-F 'jsonBody={"id":"foo","name":"bar"};type=application/json' \
'http://localhost:8080/localproject/rest-resource/items'
卷曲日志:
* Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 8080 (#0)
> POST /localproject/rest-resource/items HTTP/1.1
> Host: localhost:8080
> Authorization: bearer 7d70fb31-0eb9-4846-9ea8-933dfb69d8f1
> USER_IP_ADDR: 127.0.0.1
> Accept: application/xml,application/xhtml+xml,application/json,text/html,text/plain
> Content-Length: 555
> Expect: 100-continue
> Content-Type: multipart/form-data; boundary=------------------------0c5f3acb5a4731ff
>
< HTTP/1.1 100 Continue
< HTTP/1.1 200 OK
< Server: Apache-Coyote/1.1
< Cache-Control: no-cache, no-store, max-age=0, must-revalidate
< Pragma: no-cache
< Expires: 0
< X-XSS-Protection: 1; mode=block
< X-Frame-Options: DENY
< X-Content-Type-Options: nosniff
< Content-Type: application/xml
< Transfer-Encoding: chunked
< Date: Thu, 08 Feb 2018 10:50:06 GMT
<
* Connection #0 to host localhost left intact
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><updateResponse><id>5ce0b335-4638-474c-8c4a-9adb6c54b057</id><success>true</success></updateResponse>%
请求正文的附加前缀 "type=application/json" 似乎与 CURL 有所不同。没有找到任何方法可以对法拉第做同样的事情。
法拉第版本:0.12.2 & 0.14.0
Ruby 版本: 2.3.3
Rails: 5.2
任何帮助将不胜感激。
发现 Faraday 不支持混合多部分请求(文件上传 json/xml 数据)。这是因为混合文件和 json 数据不是 restful 方法,应该完全避免。此处正在进行更多讨论 https://github.com/lostisland/faraday/issues/769
我已通过修补 Faraday::Mulitipart
class 以允许混合 JSON 数据暂时解决了这个问题,
class Faraday::Request::Multipart
def create_multipart(env, params)
boundary = env.request.boundary
parts = process_params(params) do |key, value|
if (JSON.parse(value) rescue false)
Faraday::Parts::Part.new(boundary, key, value, 'Content-Type' => 'application/json')
else
Faraday::Parts::Part.new(boundary, key, value)
end
end
parts << Faraday::Parts::EpiloguePart.new(boundary)
body = Faraday::CompositeReadIO.new(parts)
env.request_headers[Faraday::Env::ContentLength] = body.length.to_s
return body
end
end
但从长远来看,应该更改服务器实现以避免混合多部分请求。
不确定它是否适合其他人,但我尝试 POST 的服务器将接受 json 作为文件部分(而不是邮件正文)。在这种情况下,这样的事情会起作用:
require 'faraday'
conn = Faraday.new("http://server:port") do |f|
f.request:multipart
f.request:url_encoded
f.adapter:net_http
end
payload = {
filePart:Faraday::UploadIO.new("image.jpg", 'image/jpeg'),
jsonPart:Faraday::UploadIO.new("stamp.json", 'application/json')
}
res = conn.post('/my/url/', payload)
puts res.body
当尝试 POST 多部分数据(文件 & json)与 Faraday gem 时,远程服务器无法识别 json 数据参数并且失败并出现验证错误它是必需的参数。
connection = Faraday.new(url: "#{uri.scheme}://#{uri.host}:#{uri.port}") do |faraday|
faraday.request :multipart
faraday.request :url_encoded
faraday.adapter :net_http
end
request_data = { file: Faraday::UploadIO.new('somefile.png', 'image/png'), jsonBody: JSON.dump({ id: 'foo', name: 'bar' }) }
response = connection.post(uri.request_uri) do |request|
request = Ff::Api::RequestHeaders.set(request, self.api_options)
request.headers['content-type'] = 'multipart/form-data; boundary=-----------RubyMultipartPost'
request.body = request_data
end
工作 CURL 请求:
curl -v -H 'Authorization: bearer 7d70fb31-0eb9-4846-9ea8-933dfb69d8f1' \
-H 'Accept: application/xml,application/xhtml+xml,application/json,text/html,text/plain' \
-H 'Content-Type: multipart/form-data' \
-F 'jsonBody={"id":"foo","name":"bar"};type=application/json' \
'http://localhost:8080/localproject/rest-resource/items'
卷曲日志:
* Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 8080 (#0)
> POST /localproject/rest-resource/items HTTP/1.1
> Host: localhost:8080
> Authorization: bearer 7d70fb31-0eb9-4846-9ea8-933dfb69d8f1
> USER_IP_ADDR: 127.0.0.1
> Accept: application/xml,application/xhtml+xml,application/json,text/html,text/plain
> Content-Length: 555
> Expect: 100-continue
> Content-Type: multipart/form-data; boundary=------------------------0c5f3acb5a4731ff
>
< HTTP/1.1 100 Continue
< HTTP/1.1 200 OK
< Server: Apache-Coyote/1.1
< Cache-Control: no-cache, no-store, max-age=0, must-revalidate
< Pragma: no-cache
< Expires: 0
< X-XSS-Protection: 1; mode=block
< X-Frame-Options: DENY
< X-Content-Type-Options: nosniff
< Content-Type: application/xml
< Transfer-Encoding: chunked
< Date: Thu, 08 Feb 2018 10:50:06 GMT
<
* Connection #0 to host localhost left intact
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><updateResponse><id>5ce0b335-4638-474c-8c4a-9adb6c54b057</id><success>true</success></updateResponse>%
请求正文的附加前缀 "type=application/json" 似乎与 CURL 有所不同。没有找到任何方法可以对法拉第做同样的事情。
法拉第版本:0.12.2 & 0.14.0
Ruby 版本: 2.3.3
Rails: 5.2
任何帮助将不胜感激。
发现 Faraday 不支持混合多部分请求(文件上传 json/xml 数据)。这是因为混合文件和 json 数据不是 restful 方法,应该完全避免。此处正在进行更多讨论 https://github.com/lostisland/faraday/issues/769
我已通过修补 Faraday::Mulitipart
class 以允许混合 JSON 数据暂时解决了这个问题,
class Faraday::Request::Multipart
def create_multipart(env, params)
boundary = env.request.boundary
parts = process_params(params) do |key, value|
if (JSON.parse(value) rescue false)
Faraday::Parts::Part.new(boundary, key, value, 'Content-Type' => 'application/json')
else
Faraday::Parts::Part.new(boundary, key, value)
end
end
parts << Faraday::Parts::EpiloguePart.new(boundary)
body = Faraday::CompositeReadIO.new(parts)
env.request_headers[Faraday::Env::ContentLength] = body.length.to_s
return body
end
end
但从长远来看,应该更改服务器实现以避免混合多部分请求。
不确定它是否适合其他人,但我尝试 POST 的服务器将接受 json 作为文件部分(而不是邮件正文)。在这种情况下,这样的事情会起作用:
require 'faraday'
conn = Faraday.new("http://server:port") do |f|
f.request:multipart
f.request:url_encoded
f.adapter:net_http
end
payload = {
filePart:Faraday::UploadIO.new("image.jpg", 'image/jpeg'),
jsonPart:Faraday::UploadIO.new("stamp.json", 'application/json')
}
res = conn.post('/my/url/', payload)
puts res.body