使用Python urllib.request请求Stripe API的身份认证问题
使用urllib.request调用Stripe API时的身份认证问题
我尝试用Python的urllib.request调用Stripe的结账会话API来获取JSON响应,但API需要身份认证,不知道怎么在请求里添加认证信息。
对应的可正常工作的curl请求如下:
curl https://api.stripe.com/v1/checkout/sessions -u pk_test_51LoUz3BgfM0E8ZiCV8UO79gw8zw7fhSgHUEAVj4wS7igs5D4kKiNsxXGeKQEUhorImNUiCxCNNtidwNkhFPUHP4i0060lsvsbw: -d success_url="http://127.0.0.1:5500/pages/success.html" -d cancel_url="http://127.0.0.1:5500/pages/nosuccess.html" -d "line_items[0][price]"=price_1LvNRkBgfM0E8ZiCTSiaNvNL -d "line_items[0][quantity]"=1 -d mode=subscription -d client_reference_id="123" -d customer_email="email@email.com" -d client_reference_id="tokenized" -d phone_number_collection["enabled"]=true
这个curl请求通过-u参数做身份认证,值为publishable key加冒号,表示无需密码,能成功创建结账会话并返回JSON。
但我的Python代码执行时返回401未授权错误:
Traceback (most recent call last): File "/home/pau/Desktop/bsnbl/Backend/borrar.py", line 17, in <module> respuesta = urllib.request.urlopen(request) File "/usr/lib/python3.8/urllib/request.py", line 222, in urlopen return opener.open(url, data, timeout) File "/usr/lib/python3.8/urllib/request.py", line 531, in open response = meth(req, response) File "/usr/lib/python3.8/urllib/request.py", line 640, in http_response response = self.parent.error( File "/usr/lib/python3.8/urllib/request.py", line 569, in error return self._call_chain(*args) File "/usr/lib/python3.8/urllib/request.py", line 502, in _call_chain result = func(*args) File "/usr/lib/python3.8/urllib/request.py", line 649, in http_error_default raise HTTPError(req.full_url, code, msg, hdrs, fp) urllib.error.HTTPError: HTTP Error 401: Unauthorized
我的Python代码如下:
import urllib.request import json # Debido a cambios en la libreria ahora se deben pasar algunos cabeceros html paymentInfo = '-u pk_test_51LoUz3BgfM0E8ZiCV8UO79gw8zw7fhSgHUEAVj4wS7igs5D4kKiNsxXGeKQEUhorImNUiCxCNNtidwNkhFPUHP4i0060lsvsbw: -d success_url="http://127.0.0.1:5500/pages/success.html" -d cancel_url="http://127.0.0.1:5500/pages/nosuccess.html" -d "line_items[0][price]"=price_1LvNRkBgfM0E8ZiCTSiaNvNL -d "line_items[0][quantity]"=1 -d mode=subscription -d client_reference_id="123" -d customer_email="abrix07@gmail.com" -d client_reference_id="tokenized" -d phone_number_collection["enabled"]=true' res = bytes(paymentInfo,'utf-8') print(str(type(res))) request = urllib.request.Request( 'https://api.stripe.com/v1/checkout/sessions', data=res, headers={ 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.47 Safari/537.36' } ) respuesta = urllib.request.urlopen(request) print('1. ',respuesta) cuerpo_respuesta = respuesta.read() print(cuerpo_respuesta) #Procesamos la respuesta json json_respuesta = json.loads(cuerpo_respuesta.decode("utf-8")) print(json_respuesta)
注:为安全起见,使用了Stripe账户的publishable key,若测试代码需使用secret key,此处无法提供,敬请谅解。
问题分析与解决方案
错误原因
你的代码把curl的命令行参数直接当作请求数据发送,完全不符合HTTP请求规范。Stripe的-u参数对应的是HTTP Basic认证,需要将密钥编码后添加到请求头中;同时请求数据需要是标准的表单编码格式,而非curl命令参数。
正确实现步骤
- 处理Basic认证:将你的publishable key(注意:创建结账会话实际应该使用Stripe的secret key,这里按你提供的密钥演示)加上冒号,进行Base64编码,然后添加到
Authorization请求头,格式为Basic <编码后的字符串>。 - 构造正确的表单数据:把curl中
-d的参数转换成键值对,再编码成application/x-www-form-urlencoded格式。 - 设置正确的请求头:添加
Content-Type: application/x-www-form-urlencoded,确保服务端能正确解析请求数据。
修正后的代码
import urllib.request import json import base64 import urllib.parse # 1. 配置认证信息 stripe_key = "pk_test_51LoUz3BgfM0E8ZiCV8UO79gw8zw7fhSgHUEAVj4wS7igs5D4kKiNsxXGeKQEUhorImNUiCxCNNtidwNkhFPUHP4i0060lsvsbw" # 构造Basic认证的编码字符串:密钥加冒号,然后base64编码 auth_str = f"{stripe_key}:" auth_bytes = auth_str.encode('utf-8') auth_base64 = base64.b64encode(auth_bytes).decode('utf-8') # 2. 构造表单数据 form_data = { "success_url": "http://127.0.0.1:5500/pages/success.html", "cancel_url": "http://127.0.0.1:5500/pages/nosuccess.html", "line_items[0][price]": "price_1LvNRkBgfM0E8ZiCTSiaNvNL", "line_items[0][quantity]": "1", "mode": "subscription", "client_reference_id": "tokenized", # 你之前重复设置了该参数,这里保留最后一个值 "customer_email": "abrix07@gmail.com", "phone_number_collection[enabled]": "true" } # 将表单数据编码为urlencoded格式 encoded_data = urllib.parse.urlencode(form_data).encode('utf-8') # 3. 创建请求对象 request = urllib.request.Request( 'https://api.stripe.com/v1/checkout/sessions', data=encoded_data, headers={ 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.47 Safari/537.36', 'Authorization': f'Basic {auth_base64}', 'Content-Type': 'application/x-www-form-urlencoded' } ) # 发送请求并处理响应 try: respuesta = urllib.request.urlopen(request) cuerpo_respuesta = respuesta.read() json_respuesta = json.loads(cuerpo_respuesta.decode("utf-8")) print(json_respuesta) except urllib.error.HTTPError as e: print(f"请求错误: {e.code} - {e.read().decode('utf-8')}")
额外提示
Stripe官方推荐使用官方的Python SDK来调用API,比直接用urllib更简单且不易出错。如果可以的话,建议安装stripe库后使用以下方式实现:
import stripe stripe.api_key = "你的secret key" session = stripe.checkout.Session.create( success_url="http://127.0.0.1:5500/pages/success.html", cancel_url="http://127.0.0.1:5500/pages/nosuccess.html", line_items=[ { "price": "price_1LvNRkBgfM0E8ZiCTSiaNvNL", "quantity": 1, }, ], mode="subscription", client_reference_id="tokenized", customer_email="abrix07@gmail.com", phone_number_collection={"enabled": True}, ) print(session)
内容的提问来源于stack exchange,提问作者user19851042
相关产品推荐
相关产品推荐

