---
# System prepended metadata

title: Python / requests
tags: [requests, session, response, curl, Python]

---

Python / requests
===
###### tags: `Python`
###### tags: `Python`, `requests`, `response`, `session`, `curl`

<br>

[TOC]

<br>

## HTTP status code
https://hackmd.io/L4FMNkarTtKU79Dp6_1iRg

<br>

## curl / python 對應關係
### GET
```curl=
curl 10.78.26.20:32586
```
```curl=
curl -X GET 10.78.26.20:32586
```
```python=
import requests

response = requests.get('http://10.78.26.20:32586')
print('status_code:', response.status_code)
print('text:', response.text)
```

### POST
```curl=
curl -X POST \
    10.78.26.20:32586/predict \
    -F file=@dataset/classification/penguin/input/test_x.csv \
    -F INPUT_CSV_WITH_HEADER=true
```
後端：
```python=
import requests
import json

my_data = {'INPUT_CSV_WITH_HEADER': True}
my_file = {'file': open('dataset/classification/penguin/input/test_x.csv', 'r')}

response = requests.post(
    'http://10.78.26.20:32586/predict', 
    data=my_data, files=my_file)

print('status_code:', response.status_code)
print('text:', response.text)
print('json:', json.loads(response.text))
```

<br>

## request / headers

### Content-Type
> 用來指定 body 的內容類型，可以是 json 格式或是其他

```
headers = {
    'content-type': 'application/json',
}
```
- Content-Type 是用來指示 data 的類型
- 若沒有定義 Content-Type，一般後端拿到的預設值為 `application/x-www-form-urlencoded`
    - 例如 flask.request.get_json() 會拿到 None
    - 因 json data 是 None，存取時就會引發 'NoneType' object is not subscriptable
- key 不區分大小寫
    - 'Content-Type'
    - 'content-type'

<br>

### Connection: keep-alive
- ### request header 有 Connection: keep-alive<br>用途為何？如果沒加會如何？
    [ChatGPT]
    Connection: keep-alive 是 HTTP 協議的一個標頭字段，用來指示客戶端與伺服器之間的連線是否應該保持開啟，以便在未來的請求中重用同一個連線。

    當使用 Connection: keep-alive 時，當一個請求完成後，TCP 連線不會立即關閉，而是保持打開的狀態，以便在稍後的請求中重用。這樣的好處包括：

    1. 減少了建立和關閉 TCP 連線的開銷，因為連線被重用。
    2. 提高了多次請求的效能，因為不需要重新建立連線。
    
    如果未提供 Connection: keep-alive，那麼預設情況下，每個 HTTP 請求都會在完成後將 TCP 連線關閉，需要重新建立連線。這樣的話，每個請求都要付出建立連線的成本，可能會影響效能。

    需要注意的是，現代的瀏覽器和伺服器通常默認啟用了 Connection: keep-alive，因此通常不需要手動添加。不過，如果有需要的話，你仍然可以明確地添加這個標頭字段。

- ### 如果 request 是 stream,   header 會預設  Connection: keep-alive  嗎？
    [ChatGPT]
    當使用 requests 套件進行 HTTP 請求時，預設情況下，Connection: keep-alive 應該是啟用的。requests 套件會在每個請求中自動添加這個標頭，以保持 TCP 連線的開啟，從而提高效能。

    當你使用 stream=True 參數時，通常表示你希望以串流的方式處理響應內容，例如下載大型文件。在這種情況下，保持連線開啟可以確保整個響應數據能夠以串流的方式逐步下載，而不是一次性下載整個內容。

    總的來說，Connection: keep-alive 的使用在現代的 HTTP 請求中是相當普遍的，並且通常由庫和工具默認啟用。

- ### 如何將 keep-alive 設為關閉？
    [ChatGPT]
    若想在 requests 中將 Connection: keep-alive 設定為關閉，你可以使用 Session 物件並調整其 keep_alive 屬性。以下是一個範例：

    ```python=
    import requests

    # 創建 Session 物件
    session = requests.Session()

    # 關閉 keep-alive
    session.keep_alive = False

    # 使用 Session 進行請求
    response = session.get('https://example.com')

    # 在完成所有請求後，最好關閉 Session
    session.close()
    ```
    這樣做將會關閉該 Session 物件的 keep-alive 功能，每次請求都會強制使用新的連線。請注意，這樣的設置可能會影響效能，因為它將阻止連線的重用。在大多數情況下，保持 keep-alive 是一個良好的實踐，因為它可以節省連接時間和資源。

<br>

## request / post

### stream=True/False
- ### 實際功用
    - 不管stream=True/False，都可以透過 `iter_lines()` 擷取
        ```python
        if True:
            for line in res.iter_lines():
                print(line)
        else:
            res.json()
        ```
- ### requests.post 的參數 stream 用途為何？為何我設了好像不起作用？
    [ChatGPT]
    stream 參數是 Python 的 requests.post 方法的一個參數，用於控制是否啟用流式傳輸。當 stream 被設置為 True 時，requests 將會使用 iter_content 方法來下載內容，這允許你一次只下載一小部分數據，而不是將整個內容全部下載到內存中。

    stream 主要用於處理大型文件或者慢速的數據源，以節省內存。但要注意，啟用 stream 後，你需要手動處理內容，通常是使用 iter_content 或 iter_lines 方法。

    以下是一個簡單的示例，展示如何使用 stream：

    ```python=
    import requests

    url = 'https://www.example.com/large-file'
    response = requests.post(url, stream=True)

    # 檢查是否成功
    if response.status_code == 200:
        # 使用 iter_content 下載內容，chunk_size 可以指定每次下載的大小
        for chunk in response.iter_content(chunk_size=128):
            # 處理下載的數據，例如保存到文件
            process_chunk(chunk)
    else:
        print(f"Request failed with status code: {response.status_code}")
    ```

    如果你的 stream 設置好像沒有起作用，可能有以下原因：

    1. **服務器不支持流式傳輸**： 當服務器不支持流式傳輸時，stream 參數可能不會生效。
    2. **服務器立即返回內容**： 如果服務器立即返回所有內容，而不是按需生成，則即使啟用了 stream，也可能會一次性下載所有內容。
    3. **網絡問題**： 檢查網絡連接是否穩定，可能存在網絡問題導致無法實現按需下載。

    請檢查以上原因，確保服務器支持流式傳輸，而且在服務器端是按需生成內容的。

    :::warning
    
    :::

<br>

## response / headers
- demo
    ```python=
    res = requests.post('http://10.78.26.241:30080/completion',
        headers={'Connection': 'keep-alive'},
        json={"n_predict": 2, "prompt": "Hello", "stream": True}, stream=True)
    print(res.headers)
    ```
    執行結果：
    ```json=
    {
        'Access-Control-Allow-Headers': 'content-type', 
        'Access-Control-Allow-Origin': '*',
        'Content-Type': 'text/event-stream',
        'Keep-Alive': 'timeout=5, max=5',
        'Server': 'llama.cpp',
        'Transfer-Encoding': 'chunked'
    }
    ```

<br>

### 查看是否是大檔案
- [requests之stream参数分析以及用with确保请求关闭](http://www.xoxxoo.com/index/index/article/id/770.html)
    - stream=True 通常用在大檔案
    - stream=False 通常用在小檔案
    - 根據 content-type 判斷檔案類型
        ```python=
        res = requests.get(url, stream=True)
        ctype = res.headers['Content-Type']
        ctype = ctype.lower()
        if ctype.find('text/html') == -1:
            res.close()
            return None
        htmlstring = res.content
        res.close()
        ```

<br>

## 參考資料
- [python requests file upload](https://stackoverflow.com/questions/22567306/python-requests-file-upload)
- [Python 使用 requests 模組產生 HTTP 請求，下載網頁資料教學](https://blog.gtwang.org/programming/python-requests-module-tutorial/)
