Python requests.Session() 随机 returns 401 即使在验证之后

Python requests.Session() randomly returns 401 even after authenticating

我一直在使用 requests.Session() 来发出带有身份验证的网络请求。也许 70% 的时间我会得到 200 的 status_code,但我偶尔也会得到 401。

由于我正在使用会话 - 我绝对肯定凭据是正确的 - 假设重复相同的确切请求可能 return 200。

一些进一步的细节:

为了避免这个问题,我尝试编写一个循环,它会休眠几秒钟并重试请求。奇怪的是,我还没有看到这实际上恢复了——相反,如果第一个请求失败,那么所有后续请求也会失败。但如果我再试一次——请求可能会在第一次尝试时成功。

请注意,我已经查看了 ,但建议使用 requests.Session(),我已经这样做了,但仍然收到 401。

这里有一些代码可以演示我到目前为止所做的尝试。

import requests
from requests_ntlm import HttpNtlmAuth
from urllib.parse import quote

# Establish requests session
s = requests.Session()
s.auth = HttpNtlmAuth(username, password)

# Update the request header to request JSON formatted output
s.headers.update({'Content-Type': 'application/json; odata=verbose', 
                   'accept': 'application/json;odata=verbose'})

def RetryLoop(req, max_tries = 5):
    ''' Takes in a request object and will retry the request
        upon failure up the the specified number of maximum 
        retries.

        Used because error codes occasionally surface even though the 
        REST API call is formatted correctly. Exception returns status code 
        and text. Success returns request object. 

        Default max_tries = 5
    '''

    # Call fails sometimes - allow 5 retries
    counter = 0

    # Initialize loop
    while True:
        # Hit the URL
        r = req

        # Return request object on success
        if r.status_code == 200:
            return r

        # If limit reached then raise exception
        counter += 1
        if counter == max_tries:
            print(f"Failed to connect. \nError code = {r.status_code}\nError text: {r.text}")

        # Message for failed retry
        print(f'Failed request. Error code: {r.status_code}. Trying again...')

        # Spacing out the requests in case of a connection problem
        time.sleep(5)

r = RetryLoop(s.get("https://my_url.com"))

我还尝试在重试循环中创建一个新会话 - 但这似乎也无济于事。而且我认为如果它是站点的临时阻止,则 5 秒的睡眠应该足够了,因为我在更短的时间内重试并获得了预期的 200。我希望看到一两次失败,然后成功。

是否存在我遗漏的潜在问题?是否有更合适的方法让我可以在出现 401 时重新尝试请求?

** 编辑:@Swadeep 指出了这个问题 - 通过将请求传递给它只调用一次请求的函数。更新后可正常工作的代码:

def RetryLoop(req, max_tries = 5):
    ''' Takes in a request object and will retry the request
        upon failure up the the specified number of maximum 
        retries.

        Used because error codes occasionally surface even though the 
        REST API call is formatted correctly. Exception returns status code 
        and text. Success returns request object. 

        Default max_tries = 5
    '''

    # Call fails sometimes - allow 5 retries
    counter = 0

    # Initialize loop
    while True:

        # Return request object on success
        if req.status_code == 200:
            return req

        # If limit reached then raise exception
        counter += 1
        if counter == max_tries:
            print(f"Failed to connect. \nError code = {req.status_code}\nError text: {req.text}")

        # Message for failed retry
        print(f'Failed request. Error code: {req.status_code}. Trying again...')

        # Spacing out the requests in case of a connection problem
        time.sleep(1)

        req = s.get(req.url)

这就是我的建议。

import requests
from requests_ntlm import HttpNtlmAuth
from urllib.parse import quote

# Establish requests session
s = requests.Session()
s.auth = HttpNtlmAuth(username, password)

# Update the request header to request JSON formatted output
s.headers.update({'Content-Type': 'application/json; odata=verbose', 'accept': 'application/json;odata=verbose'})

def RetryLoop(s, max_tries = 5):
    '''Takes in a request object and will retry the request
        upon failure up the the specified number of maximum 
        retries.

        Used because error codes occasionally surface even though the 
        REST API call is formatted correctly. Exception returns status code 
        and text. Success returns request object. 

        Default max_tries = 5
    '''

    # Call fails sometimes - allow 5 retries
    counter = 0

    # Initialize loop
    while True:
        # Hit the URL
        r = s.get("https://my_url.com")

        # Return request object on success
        if r.status_code == 200:
            return r

        # If limit reached then raise exception
        counter += 1
        if counter == max_tries:
            print(f"Failed to connect. \nError code = {r.status_code}\nError text: {r.text}")

        # Message for failed retry
        print(f'Failed request. Error code: {r.status_code}. Trying again...')

        # Spacing out the requests in case of a connection problem
        time.sleep(5)

r = RetryLoop(s)