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

Shopify Node.js(Express)应用报错No Shop Provided的解决方法及店铺类型咨询

解决Shopify应用启动时的"No Shop Provided"错误

问题场景

使用Node.js(Express.js)开发Shopify应用,每次运行项目访问时,都会收到错误提示:

No Shop Provided

报错核心代码(来自node_modules/@shopify/shopify-app-express/build/cjs/middlewares/ensure-installed-on-shop.js):

function getRequestShop(api, config, req, res) {
  if (typeof req.query.shop !== 'string') {
    config.logger.error('ensureInstalledOnShop did not receive a shop query argument', {
      shop: req.query.shop
    });
    res.status(422);
    res.send('No shop provided');
    return undefined;
  }
}

用户的index.js代码:

// @ts-check
import { join } from "path";
import { readFileSync } from "fs";
import express from "express";
import serveStatic from "serve-static";

import shopify from "./shopify.js";
import GDPRWebhookHandlers from "./gdpr.js";
import apis from "./api/index.js";

const PORT = parseInt(3003, 10);

const STATIC_PATH =
  process.env.NODE_ENV === "production"
    ? `${process.cwd()}/web/frontend/dist`
    : `${process.cwd()}/frontend/`;

const app = express();

// Set up Shopify authentication and webhook handling
app.get(shopify.config.auth.path, shopify.auth.begin());
app.get(
  shopify.config.auth.callbackPath,
  shopify.auth.callback(),
  shopify.redirectToShopifyOrAppRoot()
);
app.post(
  shopify.config.webhooks.path,
  shopify.processWebhooks({ webhookHandlers: GDPRWebhookHandlers })
);

app.get('/api/auth/callback', async (req, res) => {
  // app stores Session in its own storage mechanism
  
  const callbackResponse = shopify.auth.callback({
    rawRequest: req,
    rawResponse: res,
  });

  await apis.createSession(callbackResponse.session.toObject());
  
});


app.get("/api/session/get", async (req, res) => {

  const sessionId = await shopify.api.session.getCurrentId({
    isOnline: false,
    rawRequest: req,
    rawResponse: res,
  });

  console.log(sessionId);

  const session = await apis.getSession(sessionId);
  console.log(session);

  res.status(200).send(session.data);
});

app.get('/api/plans/check', async (req, res) => {
  const sessionId = await shopify.api.session.getCurrentId({
    isOnline: false,
    rawRequest: req,
    rawResponse: res,
  });

  const session = await apis.getSession(sessionId);

  console.log(shopify);

  const hasPayment = await shopify.api.billing.check({
    session,
    plans: req.query.plans,
    isTest: true,
  });

  res.status(200).send(hasPayment);
});

app.post('/api/plans/create', async (req, res) => {
  const sessionId = await shopify.api.session.getCurrentId({
    isOnline: false,
    rawRequest: req,
    rawResponse: res,
  });
  
  const session = await apis.getSession(sessionId);

  const hasPayment = await shopify.api.billing.check({
    session,
    plans: req.query.plans,
    isTest: true,
  });

  if (!hasPayment) {
    const confirmationUrl = await shopify.api.billing.request({
      session,
      plans: req.query.plans,
      isTest: true,
    });
    res.redirect(confirmationUrl);
  }
});

// All endpoints after this point will require an active session
app.use("/api/*", shopify.validateAuthenticatedSession());

app.use(express.json());

app.use(serveStatic(STATIC_PATH, { index: false }));

app.use("/*", shopify.ensureInstalledOnShop(), async (_req, res, _next) => {
  return res
    .status(200)
    .set("Content-Type", "text/html")
    .send(readFileSync(join(STATIC_PATH, "index.html")));
});

app.listen(PORT);

报错原因

shopify.ensureInstalledOnShop()中间件会强制检查请求的query参数中是否包含合法的shop字符串(即Shopify店铺域名)。你的根路由/*使用了这个中间件,直接访问本地服务时没有携带shop参数,因此触发错误。

解决方案

1. 从Shopify后台打开应用(推荐)

开发阶段,登录Shopify合作伙伴后台,进入你创建的测试店铺,找到你的应用并点击打开。Shopify会自动生成带shop参数的跳转链接,格式为:

http://localhost:3003?shop=你的测试店铺域名.myshopify.com

这种方式会自动完成授权流程,无需手动处理参数。

2. 手动添加shop参数访问

如果直接访问本地服务,在URL末尾手动拼接shop参数:

http://localhost:3003?shop=your-test-shop.myshopify.com

替换your-test-shop.myshopify.com为你的测试店铺域名。

3. 修正路由逻辑

你的代码中自定义了/api/auth/callback路由,这会和Shopify默认的授权回调路由冲突。建议移除这个自定义路由,在Shopify提供的默认回调流程中处理session存储,比如修改默认的auth callback配置:

app.get(
  shopify.config.auth.callbackPath,
  shopify.auth.callback(),
  async (req, res) => {
    // 在这里处理session存储
    await apis.createSession(res.locals.shopify.session.toObject());
    // 然后重定向到应用根目录
    shopify.redirectToShopifyOrAppRoot()(req, res);
  }
);

所需的店铺类型

必须使用Shopify官方店铺:

  • 开发测试用:在Shopify合作伙伴后台创建的测试店铺,域名格式为xxx.myshopify.com
  • 生产环境:已安装你的应用的正式Shopify店铺,同样需要使用xxx.myshopify.com格式的域名(自定义域名无法直接用于授权流程)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 21:57:56