2024년 2월 20일 화요일

python requests 사용시 multipart 로 사용하는 방법

python requests 를 사용해서 post를 사용하다면, 기본적으로 application/x-www-form-urlencoded 을 기본적으로 사용하게 됩니다.

그런데 간혹 multipart/form-data 를 원하는 경우가 있습니다.

기본 예제를 살펴 보겠습니다.

import requests

url = 'http://127.0.0.1:5000/funs'
data = {"key1": "value1", "key2": "value2"}

r = requests.post(url, data=data)
print(r.request.headers)
print(r.request.body)

위와 같이 사용하게 되면 'Content-Type': 'application/x-www-form-urlencoded' 이 됩니다.

{'User-Agent': 'python-requests/2.28.1', 'Accept-Encoding': 'gzip, deflate, br', 'Accept': '*/*', 'Connection': 'keep-alive', 'Content-Length': '23', 'Content-Type': 'application/x-www-form-urlencoded'}
key1=value1&key2=value2

그렇다면 multipart 가 되는 조건은 뭘까요?

파일을 첨부 할때입니다.

파일 첨부 예를 만들어 보겠습니다.

import requests

url = 'http://127.0.0.1:5000/funs'
data = {"key1": "value1", "key2": "value2"}

files1 = {'fl': open('test.txt', 'rb')}
r = requests.post(url, files=files1)
print(r.request.headers)
print(r.request.body)


{'User-Agent': 'python-requests/2.28.1', 'Accept-Encoding': 'gzip, deflate, br', 'Accept': '*/*', 'Connection': 'keep-alive', 'Content-Length': '149', 'Content-Type': 'multipart/form-data; boundary=40aac4e5ef113fc32999aeb43e78702e'}
b'--40aac4e5ef113fc32999aeb43e78702e\r\nContent-Disposition: form-data; name="fl"; filename="test.txt"\r\n\r\ntest123\r\n--40aac4e5ef113fc32999aeb43e78702e--\r\n'

결과가 알아보기 어렵게 되긴했지만 'Content-Type': 'multipart/form-data; 가 된것을 알 수 있습니다. 뒤에 있는 boundary는 여러개를 구분하는 용도로 사용하게 됩니다.

처음으로 돌아와서 그렇다면 어떻게 하면 data를 multipart로 전달이 가능할까요?

다른 패키지를 사용하는 방법도 있지만, requests에서는 files와 같이 보내는 방법이 있습니다.

그런데 파일을 보내지 않고 싶은데 어떻게 하냐고요? dummy로 임의의 변수를 넣어 주면 됩니다.

최종 해결책입니다.

import requests

url = 'http://127.0.0.1:5000/funs'
data = {"key1": "value1", "key2": "value2"}


files_dummy = {'fl': None}
r = requests.post(url, data=data, files=files_dummy)
print(r.request.headers)
print(r.request.body)

리턴값입니다.

{'User-Agent': 'python-requests/2.28.1', 'Accept-Encoding': 'gzip, deflate, br', 'Accept': '*/*', 'Connection': 'keep-alive', 'Content-Length': '220', 'Content-Type': 'multipart/form-data; boundary=21825c01c73525d71646d70babe7f0b5'}
b'--21825c01c73525d71646d70babe7f0b5\r\nContent-Disposition: form-data; name="key1"\r\n\r\nvalue1\r\n--21825c01c73525d71646d70babe7f0b5\r\nContent-Disposition: form-data; name="key2"\r\n\r\nvalue2\r\n--21825c01c73525d71646d70babe7f0b5--\r\n'

위에서 'fl' 이란 부분을 보냈는데 requests body부분을 살펴보면 관련 내용이 없음을 알 수 있습니다.


여기에서 사용된 server 소스 입니다.

from flask import Flask, json
from flask import request
api = Flask(__name__)

@api.route('/funs', methods=['POST'])
def post_funs():
    print(request.form)
    print(request.headers)
    return json.dumps({"success": True}), 201

if __name__ == '__main__':
    api.run(debug=True)

 


댓글 없음:

댓글 쓰기