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

Django应用配置Shopify RecurringApplicationCharge遇403错误求助

Shopify应用配置RecurringApplicationCharge返回403 ForbiddenAccess错误的解决

问题背景

基于shopify_django_app搭建的应用,尝试通过shopify.RecurringApplicationCharge配置订阅计费功能,两种实现方式均返回403 ForbiddenAccess错误。

代码示例

第一种实现代码

@shop_login_required
def buy_plan(request, id):
    plan = PlanTable.objects.get(id=id)
    context = {'plans': plan}
    charge = shopify.RecurringApplicationCharge()
    charge.name = plan.name
    charge.price = plan.price
    charge.test = True
    charge.return_url = reverse('accept')
    if charge.response_code == 201:
        confirmation_url = charge['recurring_application_charge']['confirmation_url']
        return redirect(confirmation_url)
    else:
        return render(request, 'home/billing.html', context)

第二种实现代码(参考shopify_python_api文档)

@shop_login_required
def buy_plan(request, id):
    plan = PlanTable.objects.get(id=id)
    context = {'plans': plan}
    charge = shopify.RecurringApplicationCharge.create({'name' : plan.name,'price' : plan.price, 'test' : True,'return_url' : reverse('accept')})
    if charge.response_code == 201:
        confirmation_url = charge['recurring_application_charge']['confirmation_url']
        return redirect(confirmation_url)
    else:
        return render(request, 'home/billing.html', context)

URLs配置

path('buy_plan/<str:id>', views.buy_plan, name='buy_plan'),
path('accept', views.accept, name='accept'),

模板代码(billing.html)

{% extends "base.html" %}
{% block content %}
  
<h2>Plans</h2>
{% if plans %}
<div class="product-list">
  {% for plan in plans %}
  <div class="product-card">
    
    <div class="product-info">
      <h1><b>Name: </b>{{plan.name}}</h1>
      <h2><b>Price: </b>{{plan.price}}</h2>
      <a href="{% url 'buy_plan' plan.id %}">
        <button class="custom-btn btn-2">Activate</button>
      </a>
    </div>
  </div>
  {% endfor %}
</div>
{% else %}
  <em class="note">There are no plans.</em>
{% endif %}

{% endblock %}

错误信息

ForbiddenAccess at /buy_plan/1
Response(code=403, body="b''", headers={'Date': 'Fri, 18 Aug 2023 12:52:49 GMT', ...}, msg="Forbidden")

原因分析与解决办法

1. API权限缺失

  • 检查Shopify后台应用的API权限,确保已勾选read_own_subscription_contracts和write_own_subscription_contracts权限,且应用安装时已获取到这些权限。
  • 确认使用的Shopify API版本兼容性:旧版RecurringApplicationCharge已逐步被Subscription API替代,若使用较新的API版本,需切换到新的订阅接口。

2. 请求未正确发起(第一种代码的致命错误)

第一种代码仅创建了RecurringApplicationCharge实例,但未调用charge.save()方法向Shopify API发起请求,直接判断response_code完全无效。正确做法是调用save()或使用第二种代码的create()方法。

3. Return URL配置错误

  • return_url必须是完整的绝对URL,且属于应用后台配置的授权域名。原代码中reverse('accept')返回的是相对路径,需拼接成绝对URL:
    return_url = request.build_absolute_uri(reverse('accept'))
    
  • 确认accept路径在Shopify后台的"重定向URL"列表中已配置。

4. 测试模式限制

测试模式仅支持Shopify合作伙伴后台创建的开发店铺,普通店铺无法使用测试计费请求。确保当前使用的是开发店铺进行测试。

5. API客户端上下文失效

检查@shop_login_required装饰器是否正确初始化了Shopify API客户端,可在函数中添加调试代码确认:

print(shopify.ShopifyResource.site)

若输出的站点信息不包含有效访问令牌,需排查登录态维护逻辑。

修正后的代码示例

@shop_login_required
def buy_plan(request, id):
    plan = PlanTable.objects.get(id=id)
    # 修复模板循环问题:将单个plan转为列表
    context = {'plans': [plan]}
    try:
        # 生成绝对return_url
        return_url = request.build_absolute_uri(reverse('accept'))
        charge = shopify.RecurringApplicationCharge.create({
            'name': plan.name,
            'price': plan.price,
            'test': True,
            'return_url': return_url
        })
        # 直接通过属性获取确认URL,无需字典取值
        if charge.confirmation_url:
            return redirect(charge.confirmation_url)
        else:
            print(f"Charge creation failed: {charge.errors}")
            return render(request, 'home/billing.html', context)
    except shopify.ForbiddenAccess as e:
        print(f"Forbidden error details: {e}")
        return render(request, 'home/billing.html', context)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 07:37:19