我正在为 Flask 应用程序使用 Python 请求库,该应用程序托管在 Heroku 上。我使用线程实现了一个任务,它将无限期地从其他应用程序获取数据,直到用户自己停止它。理论上,每个用户都有自己的访问令牌和用于 api 调用的刷新令牌,但不知何故,有时 api 请求会发送到错误的帐户。例如,如果用户 A 和 B 都运行该应用程序,则用户 A 收到一封电子邮件,说他们获得了项目 X,但是当用户 A 检查另一个应用程序时,它不会显示项目 X,而是显示用户B 得到了该物品 X。这里可能出了什么问题?我怀疑我使用请求的方式,但我想不出任何原因。令人困惑的部分是它使用正确的用户设置来获取项目,并且仅“尝试”获取满足设置的项目,但项目只是发送到错误的帐户。
def process_search():
user = request.user
user.update_user_running_status(True)
user.set_running_session()
user.refresh()
# Custom class I made to take the user info, which has token information for the other app
itemHandler = Handler(user)
thread = Thread(target=itemHandler.start)
thread.daemon = True
thread.start()
running_status = user.running_status
current_running_session = user.current_running_session
return jsonify({'is_running': running_status, "current_running_session": current_running_session}), 200
class Handler:
allHeaders = {
"TokenRequest": {
"x-acme-identity-auth-domain": "api.acme.com",
"User-Agent": "Acme Device Acme/0.0/iOS/15.2/iPhone",
},
"AllRequest": {
"Accept": "application/json",
"x-acme-access-token": None,
"X-Acme-Date": None,
"Accept-Encoding": "gzip, deflate, br",
"Accept-Language": "en-US",
"Content-Type": "application/json",
"User-Agent": "iOS/16.1 (iPhone Darwin) Model/iPhone Platform/iPhone14,2 AcmeOS/2.112.2",
"Connection": "keep-alive",
},
}
def __init__(self, user: User) -> None:
self.user = user
self.requestHeaders = Handler.allHeaders.get("AllRequest")
self.refreshToken = user.acme_refresh_token
self.accessToken = user.acme_access_token
if self.refreshToken == "":
self.registerAccount()
self.requestHeaders["x-acme-access-token"] = self.accessToken
self.requestHeaders["X-Acme-Date"] = self.getDate()
def registerAccount(self):
auth_response = self.user.auth_response
parsed_query = parse_qs(urlparse(auth_response).query)
reg_access_token = unquote(parsed_query['openid.oa2.access_token'][0])
device_id = secrets.token_hex(16)
acme_reg_data = {
"auth_data": {"access_token": reg_access_token},
"cookies": {"domain": ".acme.com", "website_cookies": []},
"device_metadata": {
"android_id": "52aee8aecab31ee3",
"device_os_family": "android",
"device_serial": device_id,
"device_type": "A1MPSLFC7L5AFK",
"mac_address": secrets.token_hex(64).upper(),
"manufacturer": MANUFACTURER,
"model": DEVICE_NAME,
"os_version": "30",
"product": DEVICE_NAME,
},
"registration_data": {
"app_name": APP_NAME,
"app_version": APP_VERSION,
"device_model": DEVICE_NAME,
"device_serial": device_id,
"device_type": "A1MPSLFC7L5AFK",
"domain": "Device",
"os_version": OS_VERSION,
"software_version": "130050002",
},
"requested_extensions": ["device_info", "customer_info"],
"requested_token_type": [
"bearer",
"mac_dms",
"store_authentication_cookie",
"website_cookies",
],
"user_context_map": {"frc": self.generate_frc(device_id)},
}
reg_headers = {
"Content-Type": "application/json",
"Accept-Charset": "utf-8",
"x-acme-identity-auth-domain": "api.acme.com",
"Connection": "keep-alive",
"Accept": "*/*",
"Accept-Language": "en-US",
}
res = requests.post(
Handler.routes.get("GetAuthToken"),
json=acme_reg_data,
headers=reg_headers,
verify=True,
)
if res.status_code != 200:
print("login failed")
exit(1)
res = res.json()
tokens = res['response']['success']['tokens']['bearer']
self.accessToken = tokens['access_token']
self.refreshToken = tokens['refresh_token']
self.user.update_acme_token(self.accessToken, self.refreshToken)
def start(self):
while True:
if not self.user.running_status:
Offer(self.user).delete_temp_offers()
break
# fetch data
response = requests.post(
self.routes.get("getItems"),
headers=self.requestHeaders,
json={
"apiVersion": "V2",
}
)
我怀疑是requests.Session,所以改成常规请求,但问题还是出现。
这是一个经典的 Python bug,只是以巧妙的方式隐藏起来。
当你这样做时:
self.requestHeaders = Handler.allHeaders.get("AllRequest")
您没有复制该字典。执行此操作的每个对象都将获得对该同一字典的引用。当您修改字典以设置当前用户的令牌时,您正在修改所有这些。
如果您将其更改为:
self.requestHeaders = Handler.allHeaders["AllRequest"].copy()
或者,更好的是,只需初始化
__init__
中的字典,那么您的问题就会消失。