Python requests.Session() 随机 returns 401 即使在验证之后
Python requests.Session() randomly returns 401 even after authenticating
我一直在使用 requests.Session() 来发出带有身份验证的网络请求。也许 70% 的时间我会得到 200 的 status_code,但我偶尔也会得到 401。
由于我正在使用会话 - 我绝对肯定凭据是正确的 - 假设重复相同的确切请求可能 return 200。
一些进一步的细节:
我正在使用 SharePoint REST API
我正在使用 NTLM 身份验证
为了避免这个问题,我尝试编写一个循环,它会休眠几秒钟并重试请求。奇怪的是,我还没有看到这实际上恢复了——相反,如果第一个请求失败,那么所有后续请求也会失败。但如果我再试一次——请求可能会在第一次尝试时成功。
请注意,我已经查看了 ,但建议使用 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)
我一直在使用 requests.Session() 来发出带有身份验证的网络请求。也许 70% 的时间我会得到 200 的 status_code,但我偶尔也会得到 401。
由于我正在使用会话 - 我绝对肯定凭据是正确的 - 假设重复相同的确切请求可能 return 200。
一些进一步的细节:
我正在使用 SharePoint REST API
我正在使用 NTLM 身份验证
为了避免这个问题,我尝试编写一个循环,它会休眠几秒钟并重试请求。奇怪的是,我还没有看到这实际上恢复了——相反,如果第一个请求失败,那么所有后续请求也会失败。但如果我再试一次——请求可能会在第一次尝试时成功。
请注意,我已经查看了
这里有一些代码可以演示我到目前为止所做的尝试。
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)