【问题标题】:Python requests.Session() randomly returns 401 even after authenticatingPython requests.Session() 随机返回 401 即使在认证后
【发布时间】:2019-08-10 04:10:16
【问题描述】:

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

由于我使用的是会话 - 我绝对肯定凭据是正确的 - 鉴于重复的相同请求可能会返回 200。

更多细节:

  • 我正在使用 SharePoint REST API

  • 我正在使用 NTLM 身份验证

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

请注意,我已经查看了this question,但建议是使用 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)

【问题讨论】:

  • 问题是,在RetryLoop函数中,除了检查状态码和休眠之外,你什么也没做。你在睡觉后再次拨打电话的部分在哪里?除非我没有遗漏任何东西。
  • 好的 - 我明白你的意思。我认为r = req 会重新执行get 调用-但它可能在传递到RetryLoop 之前执行?这个顺序对吗?
  • 正确。 r = req 将简单地将传递给函数的响应分配给变量 r。在你的函数中,r 和 req 基本相同。
  • 解决了问题 - 我会编辑帖子。

标签: python authentication session python-requests http-status-code-401


【解决方案1】:

这就是我的建议。

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)

【讨论】:

  • 如果对您有用,请接受答案。谢谢。
猜你喜欢
  • 2020-10-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-07-13
  • 2019-03-19
  • 1970-01-01
  • 1970-01-01
  • 2019-04-26
相关资源
最近更新 更多