如何处理python中的401(未经授权)请求
我想做的是从一个站点获取,如果该请求返回401,那么重新进行身份验证摆动(可能已经过时)并重试。但是我不想第三次尝试,因为那将是我的身份验证错误。是否有人有一种很好的方法来实现这一点,而不涉及非常丑陋的代码,理想情况下是在python请求库中,但我不介意更改。我认为它没有比这更丑陋的了:如何处理python中的401(未经授权)请求,python,python-requests,Python,Python Requests,我想做的是从一个站点获取,如果该请求返回401,那么重新进行身份验证摆动(可能已经过时)并重试。但是我不想第三次尝试,因为那将是我的身份验证错误。是否有人有一种很好的方法来实现这一点,而不涉及非常丑陋的代码,理想情况下是在python请求库中,但我不介意更改。我认为它没有比这更丑陋的了: import requests from requests.auth import HTTPBasicAuth response = requests.get('http://your_url') if r
import requests
from requests.auth import HTTPBasicAuth
response = requests.get('http://your_url')
if response.status_code == 401:
response = requests.get('http://your_url', auth=HTTPBasicAuth('user', 'pass'))
if response.status_code != 200:
# Definitely something's wrong
您可以将其包装在一个函数中,并使用decorator评估响应,然后在401上重试身份验证。然后,您只需要修饰任何需要此重新验证逻辑的函数 更新: 根据要求,提供了一个代码示例。恐怕这是一段基于Python2的旧代码,但你会明白的。此操作将重试http调用多次,如
设置中所定义。NUM\u PLATFORM\u重试
,并在身份验证失败时调用刷新\u令牌
。您可以根据任何情况调整用例和结果。
然后,您可以围绕以下方法使用此装饰器:
@retry_on_read_error
def some_func():
do_something()
def retry_on_read_error(fn):
"""
Retry Feed reads on failures
If a token refresh is required it is performed before retry.
This decorator relies on the model to have a refresh_token method defined, othewise it will fail
"""
@wraps(fn)
def _wrapper(self, *args, **kwargs):
for i in range(settings.NUM_PLATFORM_RETRIES):
try:
res = fn(self, *args, **kwargs)
try:
_res = json.loads(res)
except ValueError:
# not a json response (could be local file read or non json data)
return res
if 'error' in _res and _res['error']['status'] in (401, 400):
raise AccessRefusedException(_res['error']['message'])
return res
except (urllib2.URLError, IOError, AccessRefusedException) as e:
if isinstance(e, AccessRefusedException):
self.refresh_token()
continue
raise ApiRequestFailed(
"Api failing, after %s retries: %s" % (settings.NUM_PLATFORM_RETRIES, e), args, kwargs
)
return _wrapper
你可以用这样的东西
# 401 retry strategy
import requests
from requests import Request, Session, RequestException
class PreparedRequest:
"""
Class to make Http request with 401 retry
"""
failedRequests = []
defaultBaseUrl = "https://jsonplaceholder.typicode.com"
MAX_RETRY_COUNT = 0
def __init__(self, method, endpoint,
baseurl=defaultBaseUrl, headers=None, data=None, params=None):
"""
Constructor for PreparedRequest class
@param method: Http Request Method
@param endpoint: endpoint of the request
@param headers: headers of the request
@param data: data of request
@param params: params of the request
"""
self.method = method
self.url = baseurl + endpoint
self.headers = headers
self.data = data
self.params = params
self.response = None
def send(self):
"""
To send http request to the server
@return: response of the request
"""
req = Request(method=self.method, url=self.url, data=self.data,
headers=self.headers,params=self.params)
session = Session()
prepared = session.prepare_request(req)
response = session.send(prepared)
if response.status_code == 200:
PreparedRequest.failedRequests.append(self)
PreparedRequest.refresh_token()
elif response.status_code == 502:
raise Exception(response.raise_for_status())
else:
self.response = session.send(prepared)
@staticmethod
def refresh_token():
if PreparedRequest.MAX_RETRY_COUNT > 3:
return
print("Refreshing the token")
# Write your refresh token strategy here
PreparedRequest.MAX_RETRY_COUNT += 1
total_failed = len(PreparedRequest.failedRequests)
for i in range(total_failed):
item = PreparedRequest.failedRequests.pop()
item.send()
r = PreparedRequest(method="GET", endpoint="/todos/")
r.send()
print(r.response.json())
是的,这和我的想法很相似,只是我把401向上冒泡了。酷!你可以写下你自己的答案并接受它,或者接受这个答案;我意识到你和我是世界上最聪明的两个人,但可能只有另一个人和我们一样聪明,找到了更好的方法;-)看来我们绝对是世界上最聪明的人。世界的确比我想象的更糟糕!我很想看到这样一个例子。