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

Shopify与NetSuite间第二代Google Cloud Function转发不稳定问题

问题:Shopify Webhook转发至NetSuite RESTlet间歇性返回403错误

我正尝试通过第二代Google Cloud Function将Shopify的order/create webhook数据转发至NetSuite RESTlet,采用NetSuite的TBA(基于令牌的认证)方式完成鉴权。目前该功能仅能间歇性正常工作,多数情况下会返回403错误(AxiosError: Request failed with status code 403 at settle),这说明consumer key和consumer secret至少是正确的。这是我首次使用Google Cloud Function,可能忽略了一些基础运行机制。

最新版本的代码与之前可正常运行版本的唯一区别是将script ID存储为环境变量,代码如下:

const axios = require('axios');
const crypto = require('crypto');

exports.shopifyToNetSuite = (req, res) => {

  let data = JSON.stringify(req.body);

  const realm = process.env.REALM;
  const consumerKey = process.env.CONSUMER_KEY;
  const consumerSecret = process.env.CONSUMER_SECRET;
  const tokenId = process.env.TOKEN_ID;
  const tokenSecret = process.env.TOKEN_SECRET;
  const scriptId = process.env.SCRIPT_ID;

  const timestamp = generateOAuthTimestamp();
  const oauthNonce = crypto.randomBytes(16).toString('base64');
  const oauthSignature = generateOAuthSignature();

  function generateOAuthTimestamp() {
    const date = new Date();
    return Math.floor(date.getTime() / 1000);
  }

  function generateOAuthSignature() {
    // Step 1: Generate Base String
    const httpMethod = 'POST';
    const baseURL = `https://${realm}.restlets.api.netsuite.com/app/site/hosting/restlet.nl`;
    const parameters = {
      oauth_consumer_key: consumerKey,
      oauth_nonce: oauthNonce,
      oauth_signature_method: 'HMAC-SHA256',
      oauth_timestamp: timestamp,
      oauth_token: tokenId,
      oauth_version: '1.0',
      script: scriptId,
      deploy: '1'
    };

    const parameterString = Object.keys(parameters)
      .sort()
      .map((key) => `${key}=${encodeURIComponent(parameters[key])}`)
      .join('&');

    const baseString = `${httpMethod}&${encodeURIComponent(baseURL)}&${encodeURIComponent(parameterString)}`;

    // Step 2: Generate Signing Key
    const signingKey = `${encodeURIComponent(consumerSecret)}&${encodeURIComponent(tokenSecret)}`;

    // Step 3: Generate Signature
    const signature = crypto
      .createHmac('sha256', signingKey)
      .update(baseString)
      .digest('base64');

    return signature;
  }

  let config = {
    method: 'post',
    maxBodyLength: Infinity,
    url: `https://${realm}.restlets.api.netsuite.com/app/site/hosting/restlet.nl?script=${scriptId}&deploy=1`,
    headers: {
      'Content-Type': 'application/json',
      'Authorization': `OAuth realm="${realm}",oauth_consumer_key="${consumerKey}",oauth_token="${tokenId}",oauth_signature_method="HMAC-SHA256",oauth_timestamp="${timestamp}",oauth_nonce="${oauthNonce}",oauth_version="1.0",oauth_signature="${oauthSignature}"`,
    },
    data: data
  };

  axios.request(config)
    .then((response) => {
      console.log(JSON.stringify(response.data));
    })
    .catch((error) => {
      console.log(error);
    });

};

我已尝试过一些排查措施,但均未解决问题:

  • 将User-Agent请求头改为Mozilla/5(因Shopify默认发送的是"Shopify-Captain-Hook",曾看到论坛提到Suitelets不接受该头,推测RESTlet可能也有此限制,但调整后无效果);
  • 使用oauth-1.0a包构建请求,但未成功。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 15:02:03