You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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' %}">&#x2190; 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-&currency=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>
  • 控制台报错截图:控制台跨站Cookie报错
  • 展开后的报错详情:报错详情
  • 历史正常运行效果:支付门户正常效果
解决方案

先修复阻断渲染的显性代码错误

现有代码里存在直接触发JS运行错误的问题,这是按钮无法渲染的核心诱因,和Cookie报错无关:

  1. onApprove回调中,注释了element变量的定义语句,但后续直接调用element.innerHTML,会抛出ReferenceError: element is not defined,直接中断整个PayPal按钮的初始化渲染流程。要么放开const element = document.getElementById('paypal-button-container');的注释,要么直接删除这两行element相关的DOM操作代码。
  2. 支付成功后存在重复跳转逻辑:actions.redirect('home.html')和后续submitFormData里的window.location.href跳转冲突,删掉actions.redirect('home.html')即可,统一用后端处理完成后的跳转逻辑。
  3. fetch请求头里的Content-Type值拼写错误,applicaiton/json应为application/json,否则后端无法正常解析提交的订单数据。

解决跨站Cookie报错

自行修改站点SameSite属性没有效果,因为被拦截的是PayPal域名下的第三方Cookie,无法控制PayPal服务端的Cookie配置,按以下步骤调整:

  1. 给加载PayPal JS SDK的script标签添加crossorigin="use-credentials"属性,适配现代浏览器跨站资源加载的身份凭证传递规则。
  2. 确保站点运行在HTTPS协议下:不管是本地测试还是生产环境,HTTP协议会被浏览器判定为不安全上下文,直接拦截所有第三方Cookie。本地测试可以用mkcert生成本地证书,通过host映射自定义本地域名(如https://dev.yourproject.com)访问,不要直接用http://localhost或http://127.0.0.1。
  3. 到PayPal开发者后台,将站点域名(包括本地测试域名)添加到对应应用的允许域名列表中,否则PayPal会主动拒绝跨域请求,导致SDK加载失败。
  4. 当前代码里写的client-id是公开的沙盒测试ID,仅能用于功能测试,正式上线前必须替换为自己账号下生成的正式环境client-id。

内容的提问来源于stack exchange,提问作者Kyle Feldman

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 21:36:14