ํ์ฌ ๋ฉํฐํํธ ์์ ์์ฒญ์ ํ ์ ์๋ ์ ์ผํ ๋ฐฉ๋ฒ์ r = requests.post(url, data=payload, files=files)
๊ตฌ์ฑ ์์๊ฐ์์ ์ ์์ต๋๋ค
Content-Disposition: form-data; name="file"; filename="filename.txt"
Content-Type: text/plain
content
--3eeaadbfda0441b8be821bbed2962e4d--
๊ทธ๋ฌ๋ ๊ฒ์๋ฌผ์ด ๋ค์๊ณผ ๊ฐ์ด ์ฐ๊ฒฐ๋ ํ์ผ ์์ด ๋ฉํฐํํธ ํ์์ด์ด์ผ ํ๋ ๊ฒฝ์ฐ๊ฐ ์์ต๋๋ค.
Content-Disposition: form-data; name="key1"
value1
--3eeaadbfda0441b8be821bbed2962e4d
๊ทธ๋ฌ๋ ํ์๋ ์ ์ ์์ด๋ ์์ฑํ ์ ์์ต๋๋ค.
์๋ง๋ ํ์ผ์ด ์์ด๋ ๊ฒ์๋ฌผ์ ๋ค์ค ํํธ๋ก ๋ง๋๋ r = requests.post(url, data=payload, multipart=True)
์ ๊ฐ์ ํ๋๊ทธ๋ฅผ ์ถ๊ฐํ ์ ์์ต๋๋ค.
์ข์ ์๊ฐ์ฒ๋ผ ๋ค๋ฆฌ๋ฉด ์ด๋ฅผ ๊ตฌํํ๋ ์์ ์ ํ๊ฒ ๋์ด ๊ธฐ์ฉ๋๋ค.
์ด๊ฒ์ ์ด์ ์ ๋ ผ์๋์์ต๋๋ค. @kennethreitz ๊ฐ
๊ฐ์ธ์ ์ผ๋ก API์ ์ฌ์ (ํํ ๋ชฉ๋ก ๋ฑ)์์ ๋ฉํฐํํธ ๋ฐ์ดํฐ๋ฅผ ์์ฑํ๋ ํจ์๋ฅผ ๋ ธ์ถํ์ฌ ์ฌ์ฉ์๊ฐ ์ด๋ฅผ ์ฌ์ฉํ๊ณ ์์ฑ๋ ๋ฐ์ดํฐ๋ฅผ ์์ฒญ์ ์ ๋ฌํ ์ ์๋๋ก ํ๋ ๊ฒ์ด ๋ ์ข์ต๋๋ค. ํ๋ฉด์ ์ผ๋ก, ๊ทธ๋ค์ด ํ์ผ์ ์ฌ์ฉํ์ง ์๋๋ค๋ฉด, ์์ฒญ๋ ๋ฉ๋ชจ๋ฆฌ ํํธ๊ฐ ์์ด์ผ ํ์ง๋ง, ๊ทธ๋ผ์๋ ๋ถ๊ตฌํ๊ณ ๊ทธ๋ค์ ์ด๋ฏธ ๋ฉ๋ชจ๋ฆฌ์ ํ๋์ ๊ฑฐ๋ํ ๋ฌธ์์ด์ ๊ฐ์ง๊ณ ์๊ณ , ๋ ๋ฒ์งธ๋ ์ค์ ๋ก ๊ทธ๋ค์ ์ฃฝ์ด์ง ์์ ๊ฒ์ด๊ณ ๊ทธ๊ฒ์ ์ฐ๋ฆฌ๊ฐ ์๋ ๊ทธ๋ค์ ์๋ชป์ผ ๊ฒ์ ๋๋ค. .
์๋ง๋ @kennethreitz ๋ ๋ ๋ฒ์งธ ์๋ฃจ์ ์ ๋
์ค์ ๋ก ํ์ฌ API๋ ํ์ผ ์ด์ธ์ ๋ฉํฐํํธ ๋ฐ์ดํฐ ์ ์ก์ ์ง์ํ์ง ์์ผ๋ฉฐ ์ด๊ฒ์ ๋์ ๊ฒ์ ๋๋ค. ๋ฌธ์ #935 ๋ฐ shazow/urllib3/issues/120 ์ฐธ์กฐ
์ด์ฉ๋ฉด ๋ด๊ฐ ๋ญ๊ฐ๋ฅผ ๋์น๊ณ ์์์ง๋ ๋ชจ๋ฅด์ง๋ง ๊ทธ ๋ณํ๋ ๋์๊ฒ ๋ค์ ์ฌ์ํ ๊ฒ์ฒ๋ผ ๋ณด์
๋๋ค. ์ ์ฅ์๋ฅผ ๋ถ๊ธฐํ๊ณ ๋ด ๋ฒ์ ์ ์ ์๋ ๋ณ๊ฒฝ ์ฌํญ์ด ์์ต๋๋ค. https://github.com/spacecase/requests/commit/45b0b3ce1e76b241b323570a5fc88ae2089c3c3d
(์ด ์์
์ ์ํํ๋ ๋ ์ข์ ๋ฐฉ๋ฒ์ด ์๋ค๋ฉด ์๋ ค์ฃผ์ญ์์ค. ์ ๋ github์ ์ต์ํ์ง ์์ต๋๋ค.)
๋ช ๊ฐ์ ๋จ์ ํ ์คํธ๊ฐ ํ์ํ ์๋ ์๊ณ api.py์ ๋ ์คํธ๋ง์ ๋ณ๊ฒฝํด์ผ ํ ์๋ ์์ง๋ง ์ด์ ๊ฐ์ ๊ฒ์ด ํฉ๋ฆฌ์ ์ ๋๊น?
๋ณ๊ฒฝ ์ฌํญ์ ๋ฌธ์ ๋ ๊ตฌํ์ด ๋ณต์กํ๋ค๋ ๊ฒ์ด ์๋๋ผ API์ ์ฐจ์ด์
๋๋ค. ์ ๋ ์ด ์งํ ์ค์ธ ํ ๋ก ์์ ์ผ์ข
์ ๊ฒฝ๊ณ์ ์ ์์ต๋๋ค. ์ฌ๋ฌ ๋ถ๋ถ์ผ๋ก ๊ตฌ์ฑ๋ ์์ ๋ฐ์ดํฐ๋ฅผ ์
๋ก๋ํ๋ ์ข์ ๋ฐฉ๋ฒ์ด ์์ผ๋ฉด ์ ์ฉํ ๊ฒ์ด๋ผ๊ณ ์๊ฐํ์ง๋ง ํ์ฌ์ files
API๋ ๋งค์ฐ ์ข์ ๋ฐฉ๋ฒ์ด๋ผ๊ณ ์๊ฐํฉ๋๋ค. . ๋๋ Request
API์ multipart
๋ฅผ ์ถ๊ฐํ๋ ๊ฒ์ด ๊ฐ ๊ธธ์ด๋ผ๊ณ ์๊ฐํ์ง _์์ต๋๋ค_.
์์งํ ์ ๋ ๊ฐ์ธ์ ์ผ๋ก ์ฝํ ์ธ ์ ํ ํค๋๋ฅผ ํตํด ์ ์ดํ๊ณ ์ถ์ง๋ง ํ์ฌ ์ฐ๋ฆฌ๊ฐ ํ๋ ๊ฒ๋ณด๋ค 100๋ฐฐ ๋ ์ค๋ฅ๊ฐ ๋ฐ์ํ๊ธฐ ์ฝ๊ณ ์๋ก์ด ์ฌ์ฉ์์๊ฒ ํผ๋์ ์ค ๊ฒ์ ๋๋ค. ๋๋ ์ด๊ฒ์ ๋ํด ์ธํ๋ฆฌ์ ์์ง๋ง ์ฌ์ ํ ์ด๊ฒ์ํ์ง ์๋ ์ธก๋ฉด์์ ์ค์๋ฅผ ํ ๊ฒ์ ๋๋ค.
์์? ์ด ๊ธฐ๋ฅ ์์ฒญ์ ์๋ฝํ๋ฉด ๋๊ตฐ๊ฐ json ๋งค๊ฐ๋ณ์๊ฐ ์๋ค๊ณ ๋ถํํ ๊ฐ๋ฅ์ฑ์ด ๋์์ง๋๋ค. ๊ทธ๋ฆฌ๊ณ ๋ค๋ฅธ ์ฌ๋๋ค์ด ์ถ๊ฐ๋์์ผ๋ฉด ํ๋ ๋ ๋ง์ ๋งค๊ฐ๋ณ์๋ฅผ ์๊ฐํด๋ผ ์ ์์ ๊ฒ์ด๋ผ๊ณ ํ์ ํฉ๋๋ค. ํ์ฌ์ โโ๊ฐ์ด API๋ ํด์ผ ํ ์ผ์ ์ ํํ ์ํํ๋ฉฐ ํฌ๋ฌํํธ๊ฐ ๊ฑฐ์ ๋๋ ์ ํ ์์ต๋๋ค. ์ด๊ฒ์ ๋ณด๋ ํ ๊ฐ์ง ๋ฐฉ๋ฒ์ KISS์ ๋๋ค. ์ด๊ฒ์ ์์ฒญ์ ๋ง๋ค๊ณ ์๋ต์ ์ฝ๊ณ ์์ฐ์ค๋ฝ๊ฒ ๋ง๋๋ ํ๋ฅญํ ๊ฐ์ฒด๋ฅผ ๋ฐํํฉ๋๋ค. ๊ด๊ณ ๋ ๋๋ก ์ํํ๊ณ ๋๋จธ์ง๋ ์ฌ์ฉ์๊ฐ ์ํํฉ๋๋ค. ๋ฉํฐํํธ ์ธ์ฝ๋ฉ์ ๊ด๊ณ ํ๊ณ ๋ฌธ์ํ๋ ๋์์ธ์ ํตํด ์ํํฉ๋๋ค. ์ด์ํด ๋ณด์ผ ์ ์์ง๋ง ๋ฌธ์ํ๋์ด ์๋ํฉ๋๋ค.
_(...) ๋๊ตฐ๊ฐ๋ json ๋งค๊ฐ๋ณ์๊ฐ ์๋ค๊ณ ๋ถํํ ๊ฒ์ ๋๋ค_
json์ด multipart
๋ฏธ๋์ด ์ ํ( httpbis draft 21 )์ด ์๋ multipart
application
๋ฏธ๋์ด ์ ํ( rfc4627 )์ ํ์ ์ ํ์ด๊ธฐ ๋๋ฌธ์ ๊ทธ๋ฌํ ๋ถํ์ ๋ํ ๊ทผ๊ฑฐ๋ ์์ต๋๋ค.
_์ด๋ ค์ ๋ณด์ผ ์ ์์ต๋๋ค(...)_
์ด์ํ ๋ฐ๋ฉด์ ์์ด์๋ ์ ๋ฉ๋๋ค.
์ด์ ์๊ฒฌ์ ์ฝ์ ํ ๋ด ์
์ฅ์ ๋ฐ๋ณตํ๊ณ ์ถ์ต๋๋ค. multipart/form-data
๋ ํ์ฌ ์ฌ์ฉ๋๋ ๊ฐ์ฅ ์ผ๋ฐ์ ์ธ ๋ค์ค ๋ถ๋ถ MIME ์ ํ์ด๋ฉฐ(์ธ์ฉ ํ์ :)) ์ด๋ฅผ ์ง์ํ์ง ์๋ ๊ฒ์ ํฐ ์๋ต์
๋๋ค.
@piotr-dobrogost: ์์์ ๋งํ ๊ฒ์๋ ๋ถ๊ตฌํ๊ณ , ๋๋ ๋น์ ์ด ์ฝ๊ฐ ์ค๋๋ ฅ ์๊ฒ ์ฃผ์ฅํ ์ฃผ์ฅ์ ์ฐพ์ง ๋ชปํ์ต๋๋ค.
์์ฒญ์ MIME ์ ํ์ ์ง์ํ์ง ์์ผ๋ฉฐ ์ฌ์ฉ ์ฌ๋ก๋ฅผ ์ง์ํฉ๋๋ค. ์ด ๊ด์ ์ ์์ ๋ ์๊ฒฌ์ ์ด์ํ๊ฒ ๋ง๋ญ๋๋ค. ์๋ฅผ ๋ค์ด JSON ๋งค๊ฐ๋ณ์๊ฐ ์๋ ๊ฒ์ ๋ํ ๋ถ๋ง์ JSON ํ์์ ๋ฐ์ดํฐ๋ฅผ ์
๋ก๋ํ๋ ๊ฒ์ด ๋งค์ฐ ์ผ๋ฐ์ ์ด๊ธฐ ๋๋ฌธ์
๋๋ค. ์๋ง๋ ํ์ผ์ด ์๋ ๋ฉํฐํํธ ๋ฐ์ดํฐ๋ฅผ ์
๋ก๋ํ๋ ๊ฒ๋ณด๋ค ์์ฒญ ์ฌ์ฉ์์๊ฒ ๋ ์ผ๋ฐ์ ์ผ ๊ฒ์
๋๋ค. '์ฐ๋ฆฌ๋ multipart
์ ํน์ํ ๊ฒฝ์ฐ์ ํ์ ์ ํ๋ง 'ํ๊ธฐ ๋๋ฌธ์ ์ ๊ณตํ์ง ์์ ๊ฒ์ด๋ผ๊ณ ์ฃผ์ฅํ๋ ๊ฒ์ ์ด์ํ ๋ง์ฒ๋ผ ๋ณด์
๋๋ค.
๊ทธ๋ผ์๋ ๋ถ๊ตฌํ๊ณ ๋ฌธ์ ์ ํต์ฌ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค. API๋ ์ด ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ์์ ์ ๋๋ค. ์ด ๊ธฐ๋ฅ์ ๊ตฌํํ๋ _์๋ฆ๋ค์ด_ ๋ฐฉ๋ฒ์ ์๊ฐํด๋ด์ง ๋ชปํ๋ค๋ฉด ๊ทธ๋ฐ ์ผ์ ์ผ์ด๋์ง ์์ ๊ฒ์ ๋๋ค.
๊ทธ๋ฐ ๋ถํ์ ๋ํ ๊ทผ๊ฑฐ๊ฐ ์์ ๊ฒ์ ๋๋ค [์๋ฌธ ๊ทธ๋๋ก]
@piotr-dobrogost ๋น์ ์ ๋๋ณด๋ค ๊ฐ๋ฐ์์ ๋ฏธ๋์ ๋ํด ๋ ๋ง์ ํฌ๋ง์ ๊ฐ์ง๊ณ ์์ต๋๋ค. ๊ทธ ์ธ์๋ ์์ฒญํ ๋งค๊ฐ๋ณ์๊ฐ ์ ํํ์ง ์์ต๋๋ค. form_data
๋ณด๋ค multipart
form_data
์ ๊ฐ์ ์ด๋ฆ์ผ๋ก ํธ์ถํด์ผ ํฉ๋๋ค. ์์๋ค์ํผ (๊ฐ์ ์ ์ด์ง๋ง) multipart
๋ ๋ค์ํ ๋ฏธ๋์ด ์ ํ์ ์ฐธ์กฐํ ์ ์์ต๋๋ค.
์ด์ํ ๋ฐ๋ฉด์ ์์ด์๋ ์ ๋ฉ๋๋ค.
๋ชจ๋ ๊ฒ์ด ์ฐ์ํ ์๋ ์์ต๋๋ค(ํ์ด์ฌ์์๋).
๊ทธ๋ฆฌ๊ณ ๊ทธ๊ฒ์ ์ง์งํ์ง ์๋๋ค.
ํ์ง๋ง ์ง์๋ฉ๋๋ค. ๊ทธ๋ฌ๋ ๊ทธ ์ธ์, ์ฐ๋ฆฌ๊ฐ data
์ ๋ํด application/x-www-form-urlencoded
, files
(๋๋ files+data
)์ ๋ํ multipart/form-data
, ์ ์ฐ๋ฆฌ๋ ๋ ๋ค๋ฅธ ๋งค๊ฐ ๋ณ์๋ฅผ ํ์๋ก ํ๋๊ฐ ์ฐ๋ฆฌ๊ฐ ๊ทธ๊ฒ์ ๊ฐ์ง๊ณ ์์ ๋ ๋จ์ง multipart/form-data
๋ฅผ ์ํด?
์ํ๋ ๊ฒฐ๊ณผ๋ฅผ ์ป๊ธฐ ์ํด data
๋ฐ files
์กฐํฉ์ ์ฌ์ฉํ ํ์๊ฐ ์์ต๋๋ค. ์ค์ ํ์ผ ์์ด requests.post('http://example.com/', files=[('key1', 'param1'), ('key2', 'param2')])
์ ์ ์ฌํ ์์
์ ์ํํ ์ ์์ต๋๋ค.
๊ทธ๋ฆฌ๊ณ ์ ํํ ๋งํ๋ฉด form_data
๊ฐ ์์ ํ ๋ช
ํํ์ง ์์ ์ ์์ผ๋ฏ๋ก multipart_form_data
๋งค๊ฐ๋ณ์๋ฅผ ์ฌ์ฉํ์ง ์๋ ์ด์ ๋ ๋ฌด์์
๋๊น? ๊ทธ๊ฒ์ ๋ช
์์ ์
๋๋ค. ์, PEP 8์ ๋ช
์์ ์ผ๋ก ์๊ตฌํ์ง๋ง ๊ธฐ์กด ๋์์ ์ ๋ฌธ์ํ๋์ด ์์ต๋๋ค. @kennethreitz ๊ฐ ์ด ๊ธฐ๋ฅ ์์ฒญ์ ์๋ฝํ๊ธฐ๋ก ๊ฒฐ์ ํ ๊ฒฝ์ฐ ๋ชจ๋ ๋งค๊ฐ๋ณ์๋ ํ์ผ ๋งค๊ฐ๋ณ์์ ๋ํ ๋ณ์นญ์ผ๋ก ์๋ํด์ผ ํฉ๋๋ค. ๊ทธ๋ฌ๋ ๋์์ด ์ด๋ฏธ ์ง์๋๋ ๊ฒ์ ๊ณ ๋ คํ๋ฉด ํ์ํ์ง ์๋ค๊ณ ์๊ฐํฉ๋๋ค.
@sigmavirus24 ์ @Lukasa๋ ์ด๊ฒ์ ์๋ฒฝํ๊ฒ ์์ฝํ์ต๋๋ค.
@piotr-dobrogost ๊ทํ์ ๊ธฐ์ฌ๋ ๋์ด ํ๊ฐ๋์ง๋ง ๊ทํ์ ์ด์กฐ๋ ์๋๋๋ค. ์ฐ๋ฆฌ ํ๋ก์ ํธ์ ๋ชฉํ์ ๋ํด ํ๊ณ ํ ์ฃผ์ฅ์ ํ๋ ๊ฒ์ ์ค๋จํ์ญ์์ค.
๋ด ๊ด์ ์์๋ ์์ฒญ์ด ์ด๋ฏธ ์ฌ๋ฌ ๋ถ๋ถ์ผ๋ก ๊ตฌ์ฑ๋ ๊ฒ์๋ฌผ์ ์ง์ํ์ง๋ง ํ์ผ์ ์ฌ์ฉํ์ง ์๊ณ ๋ ์ฌ์ฉ์์๊ฒ ์ก์ธ์ค ๊ถํ์ ์ ๊ณตํ์ง ์๋๋ค๋ ์ฌ์ค์ด ์๋นํ ์ค๋ง์ค๋ฝ์ต๋๋ค. @sigmavirus24 ์ ํ์ผ์ ๊ฑฐ๊ธฐ์
๋๋ ์ด๊ฒ์ด ์์ผ๋ก๋ ์ฌ์ฉ์๋ค์๊ฒ ๊ณ์ํด์ ๋ฌธ์ ๊ฐ ๋ ๊ฒ์ด๋ผ๊ณ ์๊ฐํ๋๋ฐ, ์ ์ด๊ฒ์ ํด๊ฒฐํ๋ ค๋ ๋ ธ๋ ฅ์ด ์๋ ๊ฒ ๊ฐ์ ์กฐ๊ธ ํผ๋์ค๋ฝ์ต๋๋ค.
#935์ ๋ํ ๋ด ์๋ต ๋ณด๊ธฐ
์ค ๊ฐ์ฌ. ๊ธฐ๋๋ฉ๋๋ค!
@๋ฃจ์นด์ฌ
_Requests๋ MIME ์ ํ์ ์ง์ํ์ง ์์ผ๋ฉฐ ์ฌ์ฉ ์ฌ๋ก๋ฅผ ์ง์ํฉ๋๋ค._
multipart/form-data
๋ฐ์ดํฐ๋ฅผ ๋ณด๋ด๋ ๊ฒ์ ์ผ๋ฐ์ ์ธ ์ฌ์ฉ ์ฌ๋ก์
๋๋ค.
_(...) JSON ํ์์ ๋ฐ์ดํฐ๋ฅผ ์ ๋ก๋ํ๋ ๊ฒ์ ๋งค์ฐ ์ผ๋ฐ์ ์ ๋๋ค(...)_
json์ ๋ณด๋ด๋ ๊ฒ๊ณผ multipart/form-data
๋ฅผ ๋ณด๋ด๋ ๊ฒ์ ๋น๊ตํ ์ ์์ต๋๋ค. json์ ๋ณด๋ด๋ ๊ฒ์ ์ฝ์ต๋๋ค. Content-type
์ค์ ํ๊ณ ๋ด์ฅ ๋ชจ๋์ ์ฌ์ฉํ์ฌ ๋ฐ์ดํฐ๋ฅผ ํ ์ค๋ก ์ธ์ฝ๋ฉํ๋ฉด ๋ฉ๋๋ค. multipart/form-data
๋ณด๋ด๋ ๊ฒ์ ์์ฒญ์ ๋ณธ๋ฌธ์ด ํน์ ๊ตฌ์กฐ๋ฅผ ๊ฐ์ ธ์ผ ํ๊ธฐ ๋๋ฌธ์ ๋ ๋ณต์กํฉ๋๋ค. ์ฆ, json์ ๋ณด๋ด๋ ๊ฒ์ HTTP์ ๊ดํ ํ ํฌ๋ช
ํ์ง๋ง multipart/form-data
๋ณด๋ด๋ ๊ฒ์ ๊ทธ๋ ์ง ์์ต๋๋ค. Requests๋ HTTP ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ด๋ฏ๋ก ๊ทธ๋ฌํ ๊ตฌ์กฐ๋ฅผ ์์ฑํ๋ ๋ฐ ์ฃผ์ํด์ผ ํฉ๋๋ค.
_์ด ๊ธฐ๋ฅ์ ๊ตฌํํ๋ ์๋ฆ๋ค์ด ๋ฐฉ๋ฒ์ ์๊ฐํด๋ด์ง ๋ชปํ๋ฉด ์ผ์ด๋์ง ์์ ๊ฒ์ ๋๋ค._
ํ์ผ๊ณผ ์๋ฌด ๊ด๋ จ์ด ์๋ multipart/form-data
๋ฅผ ๋ณด๋ด๊ธฐ ์ํด ํ์ฌ files
๋งค๊ฐ๋ณ์๋ฅผ ๊ฐ๋ ๊ฒ์ ์ด๋ค ์์ผ๋ก๋ ์๋ฆ๋ต์ง ์์ง๋ง(์ถ์
ํฉ๋๋ค), ์ด๋ป๊ฒ๋ ์ฝ๋๋ฒ ์ด์ค์ ๋ค์ด๊ฐ ์ ์์์ต๋๋ค. :). ๋ ์ถํ ๊ฒ์ ์๊ฐํด๋ด๋ ๊ฒ์ ์ ๋ง ์ฝ์ต๋๋ค :)
@sigmavirus24
_(...) ๊ทธ๋ฌ๋ ๊ธฐ์กด ๋์์ ์ ๋ฌธ์ํ๋์ด ์์ต๋๋ค._
์๋ฌด๋ฆฌ ๋ง์ ๋ฌธ์๋ ๋์ API์์ ์ข์ API๋ฅผ ๋ง๋ค์ง ์์ต๋๋ค. API๊ฐ ์ข์์๋ก ๋ฌธ์๊ฐ ๋ ํ์ํฉ๋๋ค.
_(...)_์ ์ ์ฌํ ์์ ์ ํ ์ ์์ต๋๋ค.
๋ง์ต๋๋ค. ํ์ง๋ง ์ด๊ฒ์ ๋งค์ฐ ์คํด์ ์์ง๊ฐ ์๊ณ ์ง๊ด์ ์ด์ง ์์ต๋๋ค. ์ด์ ๋๊ธ์์ files
param์ ์ฌ์ฉํ๋ ๊ฒ์ด ์๋ชป๋ ์ ์ ์ค๋ช
ํ์ต๋๋ค.
๊ฒฐ๋ก : ๋ ๋์ ๊ฒ์ ์๊ฐํด๋ด๋ ค๋ฉด ํ์ฌ API๊ฐ multipart/form-data
๋ฐ์ดํฐ๋ฅผ ๋ณด๋ด๋ ๊ฒ๊ณผ ๊ด๋ จํ์ฌ ๋์๋ค๋ ๊ฒ์ ์ธ์ ํด์ผ ํฉ๋๋ค.
@์คํ์ด์ค์ผ์ด์ค
_๋ด ๊ด์ ์์๋ ์์ฒญ์ด ์ด๋ฏธ ์ฌ๋ฌ ๋ถ๋ถ์ผ๋ก ๊ตฌ์ฑ๋ ๊ฒ์๋ฌผ์ ์ง์ํ์ง๋ง ํ์ผ์ ์ฌ์ฉํ์ง ์๊ณ ๋ ์ฌ์ฉ์์๊ฒ ์ก์ธ์ค ๊ถํ์ ์ ๊ณตํ์ง ์๋๋ค๋ ์ฌ์ค์ด ์๋นํ ์ค๋ง์ค๋ฝ์ต๋๋ค._
๋์ํ๋ฉฐ ์ด๊ฒ์ด ๋ฌธ์ #935๋ฅผ ๋ง๋ ์ด์ ์ ๋๋ค.
์ด ๋ฌธ์ ๋ ์ข ๋ฃ๋์์ต๋๋ค.
@kennethreitz๋ฅผ ์ฉ์ํ์ธ์ @spacecase ์ ๋ ์ด ์์ ์์ ํ์ผ์ ์ฌ์ฉํ์ง ์์์ต๋๋ค. ๋๋ ๋น์ ์ด ์ํ๋ ๊ฒ์ ์ ํํ ํ๊ธฐ ์ํด ํ์ผ ๋งค๊ฐ๋ณ์๋ฅผ ์ฌ์ฉํ์ต๋๋ค. ํ์ผ์ ์ฌ์ฉํ๋ค๋ฉด open('filename')
๋ณด์์ ๊ฒ์
๋๋ค.
@sigmavirus24 , ๋ถํํ๋ ๊ทธ๊ฒ์ ๋ด๊ฐ ์ํ๋ ๊ฒ์ด ์๋๋๋ค. ํด๋ผ์ด์ธํธ๊ฐ ํ์ผ์์ ์ฝ๊ณ ์๋์ง ์ฌ๋ถ๋ ์ค์ํ์ง ์์ต๋๋ค. ์๋ฒ์ ์๋ ค์ฃผ๋ ๋ด์ฉ์ ๋๋ค. ๊ทํ์ ์์์ ๊ฒ์๋ฌผ ๋ณธ๋ฌธ์
Content-Disposition: form-data; name="key1"; filename="key1"
Content-Type: application/octet-stream
param1
--2f8732ee35564115a6c6e0c1032773e8
Content-Disposition: form-data; name="key2"; filename="key2"
Content-Type: application/octet-stream
param2
--2f8732ee35564115a6c6e0c1032773e8--
filename=
์ ์ฌ์ฉ์ ์ฃผ์ํ์ญ์์ค. ์๋ฒ์ ํ์ผ์ด ์ ์ก๋๊ณ ์์์ ์๋ ค์ค๋๋ค. ์น ์ฑ์์ ์ด ์๋ชป๋ ๋์์ผ๋ก ์์
ํ๋ฉด ์ค๋ฅ๊ฐ ๋ฐ์ํฉ๋๋ค.
๋ฏธ์ํ์ง๋ง, ๋ด๊ฐ ์ํ๋ ๊ฒ์ด ๋ฐ๋ก ๊ทธ๊ฒ์ด๋ผ๊ณ ๋งํ๋ ๋น์ ์ด ๋๋ฌด ์ฃผ์ ๋๊ฒ ๋งํ๋ ๊ฒ์ ๋๋ฅผ ํ๋๊ฒ ํฉ๋๋ค. ๋๋ ์์ด๋์ด์ ๋์์ ์ ๊ณตํ๊ธฐ ์ํด ์์ต๋๋ค. ๊ทธ๋ฆฌ๊ณ ๋น์ ์ ์ด ๊ฒฝ์ฐ ๋ ๋ค ์ํ์ง ์๋ ๊ฒ ๊ฐ์ต๋๋ค. ๊ด์ฐฎ์ต๋๋ค๋ง, ์ ๋ฅผ ์์ก์๋ณด๊ฒ ํ์ง ๋ง์์ฃผ์ธ์.
ํ , ํ๋์ ์๋ชป ๊ธฐ์ตํ ๊ฒ ๊ฐ์ต๋๋ค. ๋ฏธ์ํฉ๋๋ค. ๋น์ ์ ํ๋๊ฒ ํ๊ฑฐ๋ ๋ง์ ๊ฑฐ๋ ๊ธฐ๋ถ์ด ๋ค๊ฒ ํ๋ ค๋ ์๋๋ ์ ํ ์์์ต๋๋ค. multipart/form-data
๋ฅผ ์ฒ๋ฆฌํ๋ ๋ ๋์ ๋ฐฉ๋ฒ์ด ํ์ํ๋ค๋ ์ ์ ๋์ํ์ง๋ง API์ ๋ํ ์์ด๋์ด๊ฐ ์ ํ ์ฐ์ํ์ง ์๋ค๋ ์ ์๋ ์ฌ์ ํ ๋์ํ์ง ์์ต๋๋ค.
@spacecase #935์ ๋ํ ์ ๋ต๋ณ์ ์ฐธ์กฐํ์ธ์. ์ํฉ์ด ๋์์ง ๊ฒ์ ๋๋ค. ๊ทํ์ ํผ๋๋ฐฑ์ ์ค์ํ๊ณ ๋๋จํ ๊ฐ์ฌํฉ๋๋ค. :)
@spacecase ๋ ๊ทํ์ ์๊ฒฌ์ด ์ค์ํ๋ค๋ ๊ฒ์ ๋ณด์ฌ์ฃผ๋ ์ ์ค์ฒ๋ก, Content-Type
ํค๋๋ฅผ ์ค์ ํด์ผ ํ์ง๋ง ์ด๋ ์ฝ๊ฐ์ ์ฑ๊ฐ์ฌ์ผ ์ ์์ต๋๋ค.
@sigmavirus24 ๊ฐ์ฌํฉ๋๋ค. ์๋ํด๋ณด๊ฒ ์ต๋๋ค. ํธ๋ฆญ์ ํ ๊ฒ ๊ฐ์ต๋๋ค.
๋น์ ์ด ๋๋ฅผ ํ๋๊ฒ ํ ์๋๊ฐ ์๋์๋ค๋ ์ ์ ๊ฐ์ฌ๋๋ฆฝ๋๋ค. ๋๋ ๊ทธ๊ฒ์ ๋ํด ๊ธฐ๋ถ์ด ์ข์์ง๊ณ ๋น์ ์ด๋ ํ๋ก์ ํธ์ ๋ํด ์๋ฌด ๊ฒ๋ ๊ฐ์ง๊ณ ์์ง ์์ต๋๋ค.
๋ค, ์ ๊ฐ ์ด๋ค ์ฌ๋๋ค์๊ฒ๋ ๋ป๋ปํ๊ฒ ๋ค๋ฆฌ๋ ๊ฒ ๊ฐ์์ ์ธํฐ๋ท์ ์ฐ๋ ๊ฒ์ ๋ค๋ฌ์ด์ผ ํ ๊ฒ ๊ฐ์์. ๋๋ ๊ทธ๊ฒ์ ์ดํดํ์ง ๋ชปํ๊ณ ๋ค๋ฅธ ์ฌ๋๋ค๋ ๋์ ๋์ํ์ง๋ง ๋๋ ๊ทธ๊ฒ์ ๋ํด ๋ ธ๋ ฅํ๊ณ ์์ต๋๋ค. ๋๋ ๋ด ์๋ ์์ด ์ฌ๋๋ค์๊ฒ ๋ถ์พ๊ฐ์ ์ฃผ๋ ๊ฒ์ด ๋ฌด์์ธ์ง ๊นจ๋ซ๊ธฐ์ ์ถฉ๋ถํ ํฐ ํ๋ณธ ํฌ๊ธฐ๊ฐ ํ์ํ๋ค๊ณ ์๊ฐํฉ๋๋ค.
๊ฒ์ํ ํ์ผ๊ณผ ๋ช ๊ฐ์ง ํค-๊ฐ์ด ์์ต๋๋ค. ๊ทธ๋ ๋ค๋ฉด ์ด๋ฌํ mutilpart-form ์์ฒญ์ ๋ณด๋ด๋ ์ฌ๋ฐ๋ฅธ ๋ฐฉ๋ฒ์ ๋ฌด์์ ๋๊น? ๋น์ ์ด ๋๋ฅผ ๋์ธ ์ ์๊ธฐ๋ฅผ ๋ฐ๋๋๋ค.
Content-Disposition: form-data; name="up"; filename="aa.PNG"
Content-Type: image/png
file data
---------------------------7dee5302248e
Content-Disposition: form-data; name="exp"
-----------------------------7dee5302248e
Content-Disposition: form-data; name="ptext"
text
-----------------------------7dee5302248e
Content-Disposition: form-data; name="board"
DV_Studio
-----------------------------7dee5302248e--
I tried this way but only got a 504 error.
myfile=[('file',open('bb.jpg')),('exp','python'),('ptext',''),('board','DV_Studio')]
r = requests.post(url,files=myfile)
@deerstalker์ ๋ํ ์ง๋ฌธ์ StackOverflow ๋ฅผ ์ฌ์ฉํ์ธ์. ๊ทํ์ ์ง๋ฌธ์ ๋ตํ๊ธฐ ์ํด ์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํ ํ๋ก์ ํธ๊ฐ ์งํ ์ค์ ๋๋ค. sigmavirus24/requests-toolbelt
๋ํ ์ฌ๊ธฐ์์ ๋ณผ ์ ์๋ฏ์ด ์ด์ ์ StackOverflow์์ ์ด ์ง๋ฌธ์ ๋ต๋ณํ ์ ์ด
ํ์ผ ์์ด ๋ฉํฐํํธ ๊ฒ์๋ฌผ์ ์์ฑํ๋ ๊ฒ๊ณผ ๋์ผํ ๋ฌธ์ ๊ฐ ์์ต๋๋ค. ํ์ฌ๋ก์๋ requests.post(url, data=data_dict)
๋๋ requests.post(url, data=data_dict, files={})
๋ฅผ ์ํํด๋ ์ฐจ์ด๊ฐ ์์ต๋๋ค. ๊ทธ๋ฌ๋ files
ํค์๋์ ๊ธฐ๋ณธ๊ฐ์ None
์ด๋ฏ๋ก ๋ ๊ฐ์ง ๊ณ ์ ํ ๋์์ ๊ฐ์ง ์ ์์ด์ผ ํฉ๋๋ค. multipart/form-data
files={}
์ง์ ๋๋ฉฐ, application/x-www-form-urlencoded
ํ์ง ์์ ๋.
๋ด๊ฐ ๋ญ ๋์น ๊ฑฐ ์๋?
@jwoillez ์ ๊ฐ ๊ฒ์ํ ์คํ ์ค๋ฒํ๋ก ๋งํฌ๋ฅผ ํ๋ก์ฐํ์ จ๋์?
๋๋ ๊ทธ๋ ๊ฒ ์๊ฐํ์ง๋ง ๊ฑฐ๊ธฐ์ ๋ํ ๊ทํ์ ๋ต๋ณ์ ํ๋์ ํ์ผ๋ก Multipart POST๋ฅผ ๋ค๋ฃน๋๋ค. ์๋ ๋ฌธ์ ์ธ Multipart POST with no file๋ก ๋์๊ฐ์ต๋๋ค.
ํ์ผ ๊ฐ์ฒด๋ ๋ฌธ์์ด์ด ๋ ์ ์์ต๋๋ค. =) ์ํ๋ ์ ๋ณด๋ฅผ ์ ๊ณตํด์ผ ํฉ๋๋ค.
๊ทธ๋ฌ๋ ๋ด๊ฐ ๋น์ ์ ์ ์์ ๋ฐ๋ฅธ๋ค๋ฉด ๋๋ ๋ค์๊ณผ ๊ฐ์ ๊ฒฐ๊ณผ๋ฅผ ๋ณ์ง ์์๊น์?
Content-Disposition: form-data; name="file"; filename="filename.txt"
Content-Type: text/plain
content
--3eeaadbfda0441b8be821bbed2962e4d--
์ฌ๊ธฐ์ content
๋ ํ์ผ ๋์ ์ฌ์ฉํ๋๋ก ์ด๋ํ ๋ฌธ์์ด์
๋๊น?
๋๋ ์ ๋ง๋ก ์ด๊ฒ๋ง ์ซ๊ณ ์๋ค:
Content-Disposition: form-data; name="key1"
value1
--3eeaadbfda0441b8be821bbed2962e4d
์ํ์ง ์๋ ํํ์ ํ๋๋ ๊ธฐ๋ณธ๊ฐ์ผ๋ก ๋จ๊ฒจ๋ ์ ์์ต๋๋ค.
files = {'name': ('', 'content')}
์์ผ๋ก๋ StackOverflow๋ก ์ง๋ฌธ์ ๋ณด๋ด์ฃผ์ธ์. ๋ชจ๋ ์ ์ง ๊ด๋ฆฌ์๋ ์ ๊ธฐ์ ์ผ๋ก ์ด๋ฅผ ์ถ์ ํ๋ฉฐ ์ด๋ฌํ ์ง๋ฌธ์ ํ๊ธฐ์ ๋ ์ ์ ํ ๊ณณ์ ๋๋ค.
์ฐพ๋ ๋ต๋ณ์ด๋ค์ ๊ฐ์ฌํฉ๋๋ค. ์์ ์ฃ์กํฉ๋๋ค.
๋ง์ง๋ง ์ง๋ฌธ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค(๋น ํ์ผ ์ด๋ฆ, ๋น ์ฝํ ์ธ ์ง์ )?
Content-Disposition: form-data; name="file"; filename=""
Content-Type: text/plain
--3eeaadbfda0441b8be821bbed2962e4d--
ํํ์ ์ฝํ ์ธ ์น์ ์ ๋น ๋ฌธ์์ด์ ์ฌ์ฉํ์ฌ ๋น ์ฝํ ์ธ ๋ฅผ ์ ๊ณตํ ์ ์์ต๋๋ค. ๋ฌธ์ ๊ทธ๋๋ก ๋น ํ์ผ ์ด๋ฆ์ ์ ๊ณตํ ์ ์์ง๋ง ์กด์ฌํ์ง ์๋ ํ์ผ ์ด๋ฆ์ ์ ํํ ๊ฐ์ ๋ฐฉ์์ผ๋ก ์ฒ๋ฆฌ๋์ด์ผ ํฉ๋๋ค.
์ฌ๋ฌ ๊ฐ์ง ์ด์ํ ์ด์ ๋ก ๋๋๋ก ์ด ์์
์ ์ํํด์ผ ํ์ต๋๋ค.
์ด ์ฌ์ฉ ์ฌ๋ก์์ API๋ฅผ ๊ฐํํ๋ ค๋ ๋ชจ๋ ์ฌ๋์๊ฒ ์ด ์ ๊ทผ ๋ฐฉ์์ ์ ์ํฉ๋๋ค.
class ForceMultipartDict(dict):
def __bool__(self):
return True
FORCE_MULTIPART = ForceMultipartDict() # An empty dict that boolean-evaluates as `True`.
client.post("/", data={"some": "data"}, files=FORCE_MULTIPART)
๋๋ ๋๊ตฌ ๋ฒจํธ๋ฅผ ์ฌ์ฉํ๊ณ ํดํน์ ์์กดํ์ง ์์ ์ ์์ต๋๋ค.