簡體   English   中英

何時使用 `raise_for_status` 與 `status_code` 測試

[英]When to use `raise_for_status` vs `status_code` testing

我一直使用:

r = requests.get(url)
if r.status_code == 200:
    # my passing code
else:
    # anything else, if this even exists

現在我正在處理另一個問題,並決定允許其他錯誤,而是現在使用:

try:
    r = requests.get(url)
    r.raise_for_status()
except requests.exceptions.ConnectionError as err:
    # eg, no internet
    raise SystemExit(err)
except requests.exceptions.HTTPError as err:
    # eg, url, server and other errors
    raise SystemExit(err)
# the rest of my code is going here

除了可以在此級別測試各種其他錯誤之外,一種方法是否比另一種更好?

Response.raise_for_status()只是用於檢查狀態代碼的內置方法,與您的第一個示例基本相同。

這里沒有“更好”,只是關於流量控制的個人偏好。 我的偏好是在任何調用中捕獲錯誤的 try/except 塊,因為這會通知未來的程序員這些條件是某種錯誤。 if/else 不一定表示掃碼時出錯。


編輯:這是我的快速和骯臟的模式。

import time

import requests
from requests.exceptions import HTTPError

url = "https://theurl.com"
retries = 3

for n in range(retries):
    try:
        response = requests.get(url)
        response.raise_for_status()

        break

    except HTTPError as exc:
        code = exc.response.status_code
        
        if code in [429, 500, 502, 503, 504]:
            # retry after n seconds
            time.sleep(n)
            continue

        raise
      

但是,在大多數情況下,我將requests.Session子類化,制作一個處理指數退避的自定義HTTPAdapter ,並且上述內容存在於重寫的requests.Session.request方法中。 一個例子可以在這里看到。

raise_for_status()幾乎總是更好。

主要原因是它比測試status_code == 200更多,您應該充分利用久經考驗的代碼,而不是創建自己的實現。

例如,您是否知道 HTTP 標准實際上定義了五種不同的“成功”代碼? 通過測試status_code == 200 ,其中四個“成功”代碼將被誤解為失敗。

如果您不確定,請按照Ian Goldby 的回答

...但是請注意raise_for_status()不是一些神奇或非常聰明的解決方案 - 它是一個非常簡單的 function 解碼響應正文並拋出 HTTP 代碼 400-599 的異常,區分客戶端和服務器端錯誤( 在此處查看其代碼)。

尤其是客戶端錯誤響應可能包含您可能想要處理的響應正文中的有價值信息。 例如,HTTP 400 Bad Request 響應可能包含錯誤原因。

在這種情況下,不使用raise_for_status()可能會更干凈,確實涵蓋了它自己所做的所有情況。

示例代碼

try:
    r = requests.get(url)

    # process the specific codes from the range 400-599
    # that you are interested in first
    if r.status_code == 400:
        invalid_request_reason = r.text
        print(f"Your request has failed because: {invalid_request_reason}")
        return
    # this will handle all other errors
    elif r.status_code > 400:
        print(f"Your request has failed with status code: {r.status_code}")
        return

except requests.exceptions.ConnectionError as err:
    # eg, no internet
    raise SystemExit(err)

# the rest of my code is going here

實際用例

PuppetDB 的 API 使用Puppet 查詢語言 (PQL)以 HTTP 400 Bad Request 對語法上無效的查詢進行響應,並提供非常精確的錯誤信息。

請求查詢:

nodes[certname] { certname == "bastion" }

HTTP 400 響應的主體:

PQL parse error at line 1, column 29:

nodes[certname] { certname == "bastion" }
                            ^

Expected one of:

[
false
true
#"[0-9]+"
-
'
"
#"\s+"

請參閱我對使用此 API 的應用程序的拉取請求,以使其在此處向用戶顯示此錯誤消息,但請注意,它並不完全遵循上面的示例代碼。

更好有點主觀; 兩者都可以完成工作。 也就是說,作為一個相對缺乏經驗的程序員,我更喜歡Try / Except形式。 對我來說, T / E提醒我請求並不總是給你你所期望的(以if / else沒有的方式 - 但這可能只是我)。

raise_for_status()還允許您根據需要輕松為不同的錯誤類型( .HTTPError.ConnectionError )實現盡可能多或盡可能少的不同操作。 在我目前的項目中,我已經確定了下面的表格,因為無論原因如何,我都會采取相同的行動,但我仍然有興趣了解原因:

    try:
        ...
    except requests.exceptions.RequestException as e:
        raise SystemExit(e) from None

玩具實現:

import requests

def http_bin_repsonse(status_code):
    sc = status_code
    try:
        url = "http://httpbin.org/status/" + str(sc)
        response = requests.post(url)
        response.raise_for_status()

        p = response.content

    except requests.exceptions.RequestException as e:
        print("placeholder for save file / clean-up")
        raise SystemExit(e) from None
    
    return response, p

response, p = http_bin_repsonse(403)
print(response.status_code)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM