Faraday: json ๋ฐ ํŒŒ์ผ์„ multipart/form-data๋กœ ์—…๋กœ๋“œํ•˜๋Š” ๋ฐ ๋„์›€์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

์— ๋งŒ๋“  2020๋…„ 01์›” 05์ผ  ยท  3์ฝ”๋ฉ˜ํŠธ  ยท  ์ถœ์ฒ˜: lostisland/faraday

์•„๋ž˜๋Š” ๋‚ด๊ฐ€ ์—…๋กœ๋“œํ•ด์•ผ ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค

-data-binary $'

------WebKitFormBoundaryInmulX6ait6ZMLdu\r\n
Content-Disposition: form-data; name="message"; filename="blob"\r\n
Content-Type: application/json
{
 "title":"title of the message to be sent",
 "body":"body of the message to be sent",
 "attachedFileName":null,
 "attachedFileName2":null,
 "attachedFileName3":null,
 "recipientIdList":[186554]
}
 ------WebKitFormBoundaryInmulX6ait6ZMLdu--\r\n' --compressed

์„œ๋ฒ„๊ฐ€ ๋ฐ›๋Š” ์ฝ˜ํ…์ธ  ์œ ํ˜•์€ multipart/form-data ์ž…๋‹ˆ๋‹ค.

๋‚ด ํ˜„์žฌ ์ฝ”๋“œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

client = Faraday::Connection.new(url: BASE_URL) do |builder|
    builder.use :cookie_jar
    builder.use :multipart
    builder.use :url_encoded
    builder.adapter :net_http
end

message = {title: "title", body: "body of message", recipientIdList:[186554]}
payload = {message: JSON.dump(message)}

response = @client.post(URL) do |request|
    request.headers['Content-Type'] = 'multipart/form-data'
    request.body = payload
end

๊ทธ๋Ÿฌ๋‚˜ ์„œ๋ฒ„์—์„œ ๋ฐ›์€ ์‘๋‹ต์€ {"success"=>false, "errorCode"=>nil, "message"=>"Content type 'application/octet-stream' not supported", "data"=>nil} ์ž…๋‹ˆ๋‹ค.

์ฝ”๋“œ๋ฅผ ์กฐ๊ธˆ์”ฉ ์ˆ˜์ •ํ•˜๊ณ  ๋‹ค์‹œ ์‹œ๋„ํ•˜๊ณ  ๋ช‡ ์‹œ๊ฐ„ ๋™์•ˆ Google์„ ๊ฒ€์ƒ‰ํ–ˆ์ง€๋งŒ ์†”๋ฃจ์…˜์„ ์ฐพ์„ ์ˆ˜ ์—†์—ˆ์Šต๋‹ˆ๋‹ค.
๋ˆ„๊ตฐ๊ฐ€๊ฐ€ ๋‚˜๋ฅผ ๋„์šธ ์ˆ˜ ์žˆ๋‹ค๋ฉด ๋Œ€๋‹จํžˆ ๊ฐ์‚ฌํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.
๋ฏธ๋ฆฌ ๊ฐ์‚ฌ๋“œ๋ฆฝ๋‹ˆ๋‹ค

์ถ”์‹ : ์ด ๋ฌธ์ œ๋Š” https://github.com/lostisland/faraday/issues/830#issue -372589645 ๋ฐ https://github.com/lostisland/faraday/issues/769#issue -295426091 ๊ณผ ๊ด€๋ จ์ด ์žˆ๋Š” ๊ฒƒ ๊ฐ™์ง€๋งŒ ์ €๋Š” ํ•ด๊ฒฐ์ฑ…์„ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ๋„์™€์ฃผ์„ธ์š”..

๊ฐ€์žฅ ์œ ์šฉํ•œ ๋Œ“๊ธ€

๋ฌธ์ œ๋Š” ํŽ˜์ด๋กœ๋“œ๊ฐ€ ๊ตฌ์„ฑ๋˜๋Š” ๋ฐฉ์‹์— ์žˆ์Šต๋‹ˆ๋‹ค. curl -data-binary ์Šค๋‹ˆํŽซ์— ๋”ฐ๋ฅด๋ฉด ์„œ๋ฒ„๋Š” message ์–‘์‹ ๊ฐ’์ด application/json ์ฝ˜ํ…์ธ  ์œ ํ˜•์„ ๊ฐ–๊ธฐ๋ฅผ ์›ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๊ตฌ์„ฑ๋œ ํŽ˜์ด๋กœ๋“œ๋Š” ์ด๊ฒƒ์„ ์ง€์ •ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

Faraday v1.0์—์„œ ์ˆ˜์ •ํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค. ๋ฉ€ํ‹ฐํŒŒํŠธ ๋ฏธ๋“ค์›จ์–ด ์— ๋Œ€ํ•ด ์ž์„ธํžˆ ์•Œ์•„๋ณด๊ธฐโ€ฆ

-payload = {message: JSON.dump(message)}
+payload = { message: Faraday::ParamPart.new(JSON.dump(message), โ€˜application/jsonโ€™) }

ํŒจ๋Ÿฌ๋ฐ์ด v0.1x(0.17.3์—์„œ ํ™•์ธ). ์ด๊ฒƒ์€ ์—ฌ์ „ํžˆ โ€‹โ€‹๋ฉ”๋ชจ๋ฆฌ ๋‚ด IO ๊ฐœ์ฒด์—์„œ ์ฝ๋Š” "ํŒŒ์ผ"์„ ๋ณด๋ƒ…๋‹ˆ๋‹ค. ์„œ๋ฒ„๊ฐ€ ์ถ”๊ฐ€ ๋ฉ€ํ‹ฐํŒŒํŠธ ํ—ค๋” ๊ฐ’์„ ์‹ ๊ฒฝ ์“ฐ์ง€ ์•Š๊ธฐ๋ฅผ ๋ฐ”๋ž๋‹ˆ๋‹ค. ์ด ๋ฉ”์‹œ์ง€ ํ•˜๋‹จ์˜ 3์ฐจ ์š”์ฒญ์—์„œ ์ž์„ธํ•œ ๋‚ด์šฉ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

-payload = {message: JSON.dump(message)}
+{ message: Faraday::UploadIO.new(StringIO.new(JSON.dump(message)), 'application/json') }

์„œ๋ฒ„๊ฐ€ ์‘๋‹ตํ•œ ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€๋ฅผ ์–ด๋–ป๊ฒŒ ์ฒ˜๋ฆฌํ•ด์•ผ ํ• ์ง€ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค.

์ฝ˜ํ…์ธ  ์œ ํ˜• 'application/octet-stream'์€ ์ง€์›๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

application/octet-stream ์˜ ์ถœ์ฒ˜๋ฅผ ์•Œ ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์— ๋ฉ€ํ‹ฐํŒŒํŠธ ์ฝ˜ํ…์ธ  ์œ ํ˜• ๋ฌธ์ œ๋ฅผ ์ˆ˜์ •ํ•˜๋ฉด ๋ฌธ์ œ๊ฐ€ ํ•ด๊ฒฐ๋˜๊ธฐ๋ฅผ ๋ฐ”๋ž๋‹ˆ๋‹ค.

๋” ๊ถ๊ธˆํ•œ ์ ์ด ์žˆ์œผ๋ฉด ์•Œ๋ ค์ฃผ์„ธ์š”!

๋‚ด ์ž‘์—… ํ‘œ์‹œ

multipart.rb ยท GitHub ์—์„œ ์ž‘๋™ํ•˜๋Š” ์ฝ”๋“œ ์กฐ๊ฐ์„ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ฝ”๋“œ๊ฐ€ ์ฐธ์กฐ ํ•˜๋Š” RequestBin ์€ ์ผ์‹œ์ ์œผ๋กœ ์š”์ฒญ ์ •๋ณด๋งŒ ๋ณด์œ ํ•˜๋ฏ€๋กœ ์•„๋ž˜์— ์„ธ๋ถ€ ์ •๋ณด๋ฅผ ๊ธฐ๋กํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

ํŽ˜์ด๋กœ๋“œ์— ์ฝ˜ํ…์ธ  ์œ ํ˜•์ด ์—†๋Š” ์š”์ฒญ:

# AMZ/Cloudfront headers removed
Content-Type: multipart/form-data; boundary=โ€”โ€”โ€”โ€”โ€”RubyMultipartPost-10fbc5eb433c89c0eca87785f09ae45d
Connection: close
Connect-Time: 1
X-Request-Id: e802a260-56a9-4d01-a4ee-77f652380185
Content-Length: 253
Host: requestbin.io
User-Agent: Faraday v1.0.0
Accept: */*

โ€”โ€”โ€”โ€”โ€”โ€”RubyMultipartPost-10fbc5eb433c89c0eca87785f09ae45d
Content-Disposition: form-data; name=โ€œmessageโ€

{โ€œtitleโ€:โ€titleโ€,โ€body":"body of messageโ€,โ€recipientIdList":[186554]}
โ€”โ€”โ€”โ€”โ€”โ€”RubyMultipartPost-10fbc5eb433c89c0eca87785f09ae45dโ€”โ€”โ€”โ€”โ€”โ€”

WITH ์ฝ˜ํ…์ธ  ์œ ํ˜• ์š”์ฒญ(Faraday 1.0)

Content-Type: multipart/form-data; boundary=โ€”โ€”โ€”โ€”โ€”RubyMultipartPost-9d77ee5700e0658dddb09ac41fad5fa4

Connection: close
Connect-Time: 0
Content-Length: 285
User-Agent: Faraday v1.0.0
X-Request-Id: 2bbb3705-42ec-4de2-877c-2afd588ed679
Accept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3
Accept: */*
Host: requestbin.io

โ€”โ€”โ€”โ€”โ€”โ€”RubyMultipartPost-9d77ee5700e0658dddb09ac41fad5fa4
Content-Disposition: form-data; name=โ€œmessageโ€
Content-Type: application/json

{โ€œtitleโ€:โ€titleโ€,โ€body":"body of messageโ€,โ€recipientIdListโ€:[186554]}
โ€”โ€”โ€”โ€”โ€”โ€”RubyMultipartPost-9d77ee5700e0658dddb09ac41fad5fa4โ€”โ€”โ€”โ€”โ€”โ€”

WITH ์ฝ˜ํ…์ธ  ์œ ํ˜• ์š”์ฒญ(Faraday v0.17.3)

Content-Type: multipart/form-data; boundary=โ€”โ€”โ€”โ€”โ€”RubyMultipartPost-697c8614200bc0d7ae2fcc0215a2a697
Connection: close
Content-Length: 363
User-Agent: Faraday v0.17.3
X-Request-Id: af65fc06-3914-4ab6-8dbf-b347a1ac498a
Accept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3
Accept: */*
Host: requestbin.io

โ€”โ€”โ€”โ€”โ€”โ€”RubyMultipartPost-697c8614200bc0d7ae2fcc0215a2a697
Content-Disposition: form-data; name=โ€œmessageโ€; filename=โ€œlocal.path"
Content-Length: 69
Content-Type: application/json
Content-Transfer-Encoding: binary

{โ€œtitleโ€:โ€titleโ€,โ€bodyโ€:โ€body of messageโ€,โ€recipientIdListโ€:[186554]}
โ€”โ€”โ€”โ€”โ€”โ€”RubyMultipartPost-697c8614200bc0d7ae2fcc0215a2a697โ€”

๋ชจ๋“  3 ๋Œ“๊ธ€

๋ฌธ์ œ๋Š” ํŽ˜์ด๋กœ๋“œ๊ฐ€ ๊ตฌ์„ฑ๋˜๋Š” ๋ฐฉ์‹์— ์žˆ์Šต๋‹ˆ๋‹ค. curl -data-binary ์Šค๋‹ˆํŽซ์— ๋”ฐ๋ฅด๋ฉด ์„œ๋ฒ„๋Š” message ์–‘์‹ ๊ฐ’์ด application/json ์ฝ˜ํ…์ธ  ์œ ํ˜•์„ ๊ฐ–๊ธฐ๋ฅผ ์›ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๊ตฌ์„ฑ๋œ ํŽ˜์ด๋กœ๋“œ๋Š” ์ด๊ฒƒ์„ ์ง€์ •ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

Faraday v1.0์—์„œ ์ˆ˜์ •ํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค. ๋ฉ€ํ‹ฐํŒŒํŠธ ๋ฏธ๋“ค์›จ์–ด ์— ๋Œ€ํ•ด ์ž์„ธํžˆ ์•Œ์•„๋ณด๊ธฐโ€ฆ

-payload = {message: JSON.dump(message)}
+payload = { message: Faraday::ParamPart.new(JSON.dump(message), โ€˜application/jsonโ€™) }

ํŒจ๋Ÿฌ๋ฐ์ด v0.1x(0.17.3์—์„œ ํ™•์ธ). ์ด๊ฒƒ์€ ์—ฌ์ „ํžˆ โ€‹โ€‹๋ฉ”๋ชจ๋ฆฌ ๋‚ด IO ๊ฐœ์ฒด์—์„œ ์ฝ๋Š” "ํŒŒ์ผ"์„ ๋ณด๋ƒ…๋‹ˆ๋‹ค. ์„œ๋ฒ„๊ฐ€ ์ถ”๊ฐ€ ๋ฉ€ํ‹ฐํŒŒํŠธ ํ—ค๋” ๊ฐ’์„ ์‹ ๊ฒฝ ์“ฐ์ง€ ์•Š๊ธฐ๋ฅผ ๋ฐ”๋ž๋‹ˆ๋‹ค. ์ด ๋ฉ”์‹œ์ง€ ํ•˜๋‹จ์˜ 3์ฐจ ์š”์ฒญ์—์„œ ์ž์„ธํ•œ ๋‚ด์šฉ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

-payload = {message: JSON.dump(message)}
+{ message: Faraday::UploadIO.new(StringIO.new(JSON.dump(message)), 'application/json') }

์„œ๋ฒ„๊ฐ€ ์‘๋‹ตํ•œ ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€๋ฅผ ์–ด๋–ป๊ฒŒ ์ฒ˜๋ฆฌํ•ด์•ผ ํ• ์ง€ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค.

์ฝ˜ํ…์ธ  ์œ ํ˜• 'application/octet-stream'์€ ์ง€์›๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

application/octet-stream ์˜ ์ถœ์ฒ˜๋ฅผ ์•Œ ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์— ๋ฉ€ํ‹ฐํŒŒํŠธ ์ฝ˜ํ…์ธ  ์œ ํ˜• ๋ฌธ์ œ๋ฅผ ์ˆ˜์ •ํ•˜๋ฉด ๋ฌธ์ œ๊ฐ€ ํ•ด๊ฒฐ๋˜๊ธฐ๋ฅผ ๋ฐ”๋ž๋‹ˆ๋‹ค.

๋” ๊ถ๊ธˆํ•œ ์ ์ด ์žˆ์œผ๋ฉด ์•Œ๋ ค์ฃผ์„ธ์š”!

๋‚ด ์ž‘์—… ํ‘œ์‹œ

multipart.rb ยท GitHub ์—์„œ ์ž‘๋™ํ•˜๋Š” ์ฝ”๋“œ ์กฐ๊ฐ์„ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ฝ”๋“œ๊ฐ€ ์ฐธ์กฐ ํ•˜๋Š” RequestBin ์€ ์ผ์‹œ์ ์œผ๋กœ ์š”์ฒญ ์ •๋ณด๋งŒ ๋ณด์œ ํ•˜๋ฏ€๋กœ ์•„๋ž˜์— ์„ธ๋ถ€ ์ •๋ณด๋ฅผ ๊ธฐ๋กํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

ํŽ˜์ด๋กœ๋“œ์— ์ฝ˜ํ…์ธ  ์œ ํ˜•์ด ์—†๋Š” ์š”์ฒญ:

# AMZ/Cloudfront headers removed
Content-Type: multipart/form-data; boundary=โ€”โ€”โ€”โ€”โ€”RubyMultipartPost-10fbc5eb433c89c0eca87785f09ae45d
Connection: close
Connect-Time: 1
X-Request-Id: e802a260-56a9-4d01-a4ee-77f652380185
Content-Length: 253
Host: requestbin.io
User-Agent: Faraday v1.0.0
Accept: */*

โ€”โ€”โ€”โ€”โ€”โ€”RubyMultipartPost-10fbc5eb433c89c0eca87785f09ae45d
Content-Disposition: form-data; name=โ€œmessageโ€

{โ€œtitleโ€:โ€titleโ€,โ€body":"body of messageโ€,โ€recipientIdList":[186554]}
โ€”โ€”โ€”โ€”โ€”โ€”RubyMultipartPost-10fbc5eb433c89c0eca87785f09ae45dโ€”โ€”โ€”โ€”โ€”โ€”

WITH ์ฝ˜ํ…์ธ  ์œ ํ˜• ์š”์ฒญ(Faraday 1.0)

Content-Type: multipart/form-data; boundary=โ€”โ€”โ€”โ€”โ€”RubyMultipartPost-9d77ee5700e0658dddb09ac41fad5fa4

Connection: close
Connect-Time: 0
Content-Length: 285
User-Agent: Faraday v1.0.0
X-Request-Id: 2bbb3705-42ec-4de2-877c-2afd588ed679
Accept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3
Accept: */*
Host: requestbin.io

โ€”โ€”โ€”โ€”โ€”โ€”RubyMultipartPost-9d77ee5700e0658dddb09ac41fad5fa4
Content-Disposition: form-data; name=โ€œmessageโ€
Content-Type: application/json

{โ€œtitleโ€:โ€titleโ€,โ€body":"body of messageโ€,โ€recipientIdListโ€:[186554]}
โ€”โ€”โ€”โ€”โ€”โ€”RubyMultipartPost-9d77ee5700e0658dddb09ac41fad5fa4โ€”โ€”โ€”โ€”โ€”โ€”

WITH ์ฝ˜ํ…์ธ  ์œ ํ˜• ์š”์ฒญ(Faraday v0.17.3)

Content-Type: multipart/form-data; boundary=โ€”โ€”โ€”โ€”โ€”RubyMultipartPost-697c8614200bc0d7ae2fcc0215a2a697
Connection: close
Content-Length: 363
User-Agent: Faraday v0.17.3
X-Request-Id: af65fc06-3914-4ab6-8dbf-b347a1ac498a
Accept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3
Accept: */*
Host: requestbin.io

โ€”โ€”โ€”โ€”โ€”โ€”RubyMultipartPost-697c8614200bc0d7ae2fcc0215a2a697
Content-Disposition: form-data; name=โ€œmessageโ€; filename=โ€œlocal.path"
Content-Length: 69
Content-Type: application/json
Content-Transfer-Encoding: binary

{โ€œtitleโ€:โ€titleโ€,โ€bodyโ€:โ€body of messageโ€,โ€recipientIdListโ€:[186554]}
โ€”โ€”โ€”โ€”โ€”โ€”RubyMultipartPost-697c8614200bc0d7ae2fcc0215a2a697โ€”

๋„์›€์„ ์ฃผ์…”์„œ ๋Œ€๋‹จํžˆ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค, @technoweenie ! ๋‹น์‹ ์€ ๊ต‰์žฅํ•˜๋‹ค!!
์ด์ œ ์š”์ฒญ์€ ์ƒˆ๋กœ ๊ตฌ์„ฑ๋œ ํŽ˜์ด๋กœ๋“œ์—์„œ ์ œ๋Œ€๋กœ ์ž‘๋™ํ•˜๋ฉฐ ๋” ์ด์ƒ application/octet-stream ์— ๋Œ€ํ•ด ๋ถˆํ‰ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
์ข‹์€ ํ•˜๋ฃจ ๋ณด๋‚ด์‹œ๊ธฐ ๋ฐ”๋ž๋‹ˆ๋‹ค :D

์ด์ œ ์˜ˆ์ƒ๋Œ€๋กœ ์ž‘๋™ํ•œ๋‹ค๋Š” ์†Œ์‹์„ ๋“ค์œผ๋‹ˆ ๊ธฐ์ฉ๋‹ˆ๋‹ค!
์ˆ˜๊ณ  ํ•˜์…จ์Šต๋‹ˆ๋‹ค @technoweenie , ์ด ๊นŒ๋‹ค๋กœ์šด ๋ฌธ์ œ๋ฅผ ๋นจ๋ฆฌ ํ•ด๊ฒฐํ•ด ์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค ๐Ÿ‘ !

์ด ํŽ˜์ด์ง€๊ฐ€ ๋„์›€์ด ๋˜์—ˆ๋‚˜์š”?
0 / 5 - 0 ๋“ฑ๊ธ‰