Django+JS下PayPal API跨站Cookie致支付按钮无法渲染问题
问题描述
毕业设计项目开发的网站支付门户出现异常:数日前支付功能运行正常,未修改任何代码的情况下PayPal支付按钮无法渲染,控制台持续输出跨站地址Cookie相关报错。自行修改全局配置、调整SameSite属性均未解决问题。
相关参考材料
- checkout.html(集成PayPal JS SDK)完整代码
{% extends 'main.html' %} {% load static %} <!DOCTYPE html> <head> <link rel="stylesheet" type="text/css" href="{% static 'css/checkout.css' %}"> </head> <body> {% block content %} <div class="row"> <div class="col-sm-6 mt-4 mb-4"> <div class="box-element" id="form-wrapper"> <h2>Recipient Information</h2> <form id="form"> <div id="recipient-info"> <div class="form-field"> <input required class="form-control" type="text" name="recipient_first_name" placeholder="Recipient First Name.."> </div> <div class="form-field"> <input required class="form-control" type="text" name="recipient_last_name" placeholder="Recipient Last Name.."> </div> <br> <div class="form-field"> <input required class="form-control" type="email" name="recipient_email" placeholder="Recipient Email.."> </div> <div class="row ml-auto"> <label class = "mt-1" for="pickup_location">Select a pickup location: </label> <select class="mt-2 ml-2" name="pickup_location" size="4" multiple> <option value="nabatieh">Nabatieh</option> <option value="tyre">Tyre</option> <option value="saida">Saida</option> <option value="beirut">Beirut</option> </select><br><br> </div> </div> <hr> <input id="form-button" class="btn btn-success btn-block" type="submit" value="Continue"> </form> </div> <br> <div class="box-element hidden" id="payment-info"> <h2>PayPal Options</h2> <div id="paypal-button-container"></div> </div> </div> <div class="col-sm-6 mt-4 mb-4"> <div class="box-element"> <a class="btn btn-outline-dark" href="{% url 'cart' %}">← Back to Cart</a> <hr> <h3>Order Summary</h3> <hr> {% for item in items %} <div class="cart-row"> <div style="flex:2"><img class="row-image" src="{{item.product.imageURL}}"></div> <div style="flex:2"><p>{{item.product.name}}</p></div> <div style="flex:1"><p>{{item.product.price|floatformat:2}}</p></div> <div style="flex:1"><p>{{item.quantity}}</p></div> </div> {% endfor %} <h5>Items: {{order.get_cart_items}}</h5> <h5>Total: ${{order.get_cart_total|floatformat:2}}</h5> </div> </div> </div> <script src="https://www.paypal.com/sdk/js?client-id=ASbTo6tPEAlA-TQ3zYFDMuuDgSWzmybQ3E3LeE3xi2s3hN6UmiREE30_atIal3f9ui2r3Eh6oGpxmil-¤cy=USD"></script> <script> var total = '{{order.get_cart_total}}' paypal.Buttons({ // Set up the transaction createOrder: function(data, actions) { return actions.order.create({ purchase_units: [{ amount: { value: parseFloat(total).toFixed(2) } }] }); }, // Finalize the transaction onApprove: function(data, actions) { return actions.order.capture().then(function(orderData) { submitFormData() console.log('Capture result', orderData, JSON.stringify(orderData, null, 2)); var transaction = orderData.purchase_units[0].payments.captures[0]; alert('Transaction '+ transaction.status + ': ' + transaction.id + '\n\nSee console for all available details'); // Replace the above to show a success message within this page, e.g. // const element = document.getElementById('paypal-button-container'); // element.innerHTML = ''; element.innerHTML = '<h3>Thank you for your payment!</h3>'; actions.redirect('home.html'); }); } }).render('#paypal-button-container'); </script> <script type="text/javascript"> var form = document.getElementById('form') var total = '{{order.get_cart_total|floatformat:2}}' form.addEventListener('submit', function(e){ e.preventDefault() console.log('Form submitted...') document.getElementById('form-button').classList.add('hidden') document.getElementById('payment-info').classList.remove('hidden') }) function submitFormData(){ console.log('Payment button has been clicked...') var orderData = { 'total':total, } var recipientInformation = { 'recipient_first_name':null, 'recipient_last_name':null, 'email':null, 'pickup_location':null, } recipientInformation.recipient_first_name = form.recipient_first_name.value recipientInformation.recipient_last_name = form.recipient_last_name.value recipientInformation.recipient_email = form.recipient_email.value recipientInformation.pickup_location = form.pickup_location.value var url = "/process_order/" fetch(url, { method:'POST', headers:{ 'Content-Type':'applicaiton/json', 'X-CSRFToken':csrftoken, }, body:JSON.stringify({'form':orderData, 'recipient-information':recipientInformation}), }) .then((response) => response.json()) .then((data) => { console.log('Success:', data); alert('Transaction completed'); window.location.href = "{% url 'store' %}" }) } </script> {% endblock content %} </body> </html>
- 控制台报错截图:

- 展开后的报错详情:

- 历史正常运行效果:
解决方案
先修复阻断渲染的显性代码错误
现有代码里存在直接触发JS运行错误的问题,这是按钮无法渲染的核心诱因,和Cookie报错无关:
onApprove回调中,注释了element变量的定义语句,但后续直接调用element.innerHTML,会抛出ReferenceError: element is not defined,直接中断整个PayPal按钮的初始化渲染流程。要么放开const element = document.getElementById('paypal-button-container');的注释,要么直接删除这两行element相关的DOM操作代码。- 支付成功后存在重复跳转逻辑:
actions.redirect('home.html')和后续submitFormData里的window.location.href跳转冲突,删掉actions.redirect('home.html')即可,统一用后端处理完成后的跳转逻辑。 - fetch请求头里的
Content-Type值拼写错误,applicaiton/json应为application/json,否则后端无法正常解析提交的订单数据。
解决跨站Cookie报错
自行修改站点SameSite属性没有效果,因为被拦截的是PayPal域名下的第三方Cookie,无法控制PayPal服务端的Cookie配置,按以下步骤调整:
- 给加载PayPal JS SDK的script标签添加
crossorigin="use-credentials"属性,适配现代浏览器跨站资源加载的身份凭证传递规则。 - 确保站点运行在HTTPS协议下:不管是本地测试还是生产环境,HTTP协议会被浏览器判定为不安全上下文,直接拦截所有第三方Cookie。本地测试可以用mkcert生成本地证书,通过host映射自定义本地域名(如
https://dev.yourproject.com)访问,不要直接用http://localhost或http://127.0.0.1。 - 到PayPal开发者后台,将站点域名(包括本地测试域名)添加到对应应用的允许域名列表中,否则PayPal会主动拒绝跨域请求,导致SDK加载失败。
- 当前代码里写的client-id是公开的沙盒测试ID,仅能用于功能测试,正式上线前必须替换为自己账号下生成的正式环境client-id。
内容的提问来源于stack exchange,提问作者Kyle Feldman
相关产品推荐
相关产品推荐

