代码之家  ›  专栏  ›  技术社区  ›  maximus ツ

带有json和文件数据的Faraday多部分请求

  •  4
  • maximus ツ  · 技术社区  · 6 年前

    当尝试使用Faraday gem发布多部分数据(文件和json)时,远程服务器无法识别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 -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

    轨道 : 5.2

    任何帮助都将不胜感激。

    2 回复  |  直到 6 年前
        1
  •  1
  •   maximus ツ    6 年前

    发现Faraday不支持混合多部分请求(使用json/xml数据上传文件)。这是因为混合文件和json数据不是restful方法,应该完全避免。这里正在进行更多的讨论 https://github.com/lostisland/faraday/issues/769

    我已通过修补暂时修复了此问题 Faraday::Mulitipart 类以允许混合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
    

    但从长远来看,应该更改服务器实现,以避免混合多部分请求。

        2
  •  0
  •   Amber    5 年前

    不确定这是否是其他人的选项,但我尝试发布到的服务器将接受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