# [Flask]Request & Response
###### tags: `python` `flask`
在HTTP協議中,使用requests傳送請求,常見的做法有傳送GET或POST,而這邊要討論較容易發生問題的POST。
> POST提交的資料必須放在訊息主體中,但是協議中並沒有規定必須使用什麼編碼方式,從而導致提交方式的不同。服務端根據請求頭中的Content-Type欄位來獲知請求中的訊息主體是用何種方式進行編碼,再對訊息主體進行解析。
:::warning
單一requests只能依協議選擇其中一種Content-Type
:::
## Content-Type
### application/x-www-form-urlencoded
以form表單形式提交資料,一般存在於網站的登入,用來提交使用者名稱和密碼。以http://httpbin.org/post 為例,在requests中,以form表單形式傳送post請求,只需要將請求的引數構造成一個字典,然後傳給requests.post()的data引數即可。
```Python
url = 'http://httpbin.org/post'
d = {'key1': 'value1', 'key2': 'value2'}
r = requests.post(url, data=d)
print(r.text)
```
### application/json
以json串提交資料,主要是用於傳送ajax請求中,動態載入資料。
* 傳送資料前,需要把data進行json編碼。
```Python
r = requests.post(url=url, data=json.dumps(data), headers=headers)
```
* requests還提供了一個json引數,自動使用json方式傳送,而且在請求頭中也不用顯示宣告’Content-Type’:’application/json; charset=UTF-8’
```Python
r = requests.post(url=url, json=data, headers=headers)
```
### multipart/form-data
上傳檔案以multipart形式傳送post請求,只需將一檔案傳給requests.post()的files引數即可。
```Python
url = 'http://httpbin.org/post'
files = {'file': open('upload.txt', 'rb')}
r = requests.post(url, files=files)
print(r.text)
```
## 同時傳送JSON & FILE
由於只能指定一個Content-Type,所以必須將資料包在一起,並各別指定資料型態,最後由pyrequests決定整個的Content-Type。
* Request
```Python
data = {"param_1": "value_1", "param_2": "value_2"}
files = {
'json': (None, json.dumps(data, ensure_ascii=False).encode('utf-8'), 'application/json'),
'file': (os.path.basename(filename), open(filename, 'rb'), 'application/octet-stream')
}
r = requests.post(url, files=files)
print(r.text)
```
* Response
```Python
# 取得json
data = json.loads(request.form['json'])
data = data['domain']
# 取得file
cur_file = request.files['file']
filename = cur_file.filename
cur_file.save(filename)
text_arr = []
with codecs.open(filename, "r", "utf-8") as fp:
for line in fp.readlines():
text_arr.append(line.strip())
```
## 參考
[Python requests傳送post請求的一些疑點](https://codertw.com/%E7%A8%8B%E5%BC%8F%E8%AA%9E%E8%A8%80/356689/)