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

Next.js客户端与服务端组件的Nonce及CORS处理最佳实践

解决方案:Next.js对接WooCommerce Store API的CORS与Nonce管理

一、解决CORS问题:用Next.js API路由做代理

直接从客户端请求WooCommerce域名会触发跨域,最稳妥的方式是通过Next.js的API路由做中转,让客户端请求自己的域名,再由服务端转发请求到WooCommerce,完全规避CORS限制。

1. 创建API代理路由

在app/api/cart/add-item/route.ts中编写代理逻辑:

import { cookies } from 'next/headers';
import { NextResponse } from 'next/server';

export async function POST(request: Request) {
  const body = await request.json();
  const cookieStore = cookies();
  const nonce = cookieStore.get('wc_store_api_nonce')?.value;

  if (!nonce) {
    return NextResponse.json({ error: 'Nonce缺失' }, { status: 400 });
  }

  // 转发请求到WooCommerce Store API
  const wcResponse = await fetch('https://my-example-store.local/wp-json/wc/store/v1/cart/add-item', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'X-WC-Store-API-Nonce': nonce,
    },
    body: JSON.stringify(body),
  });

  // 从响应头获取新的Nonce,更新Cookie
  const newNonce = wcResponse.headers.get('X-WC-Store-API-Nonce');
  if (newNonce) {
    cookieStore.set('wc_store_api_nonce', newNonce, {
      path: '/',
      sameSite: 'lax',
      httpOnly: false, // 允许客户端读取
      maxAge: 3600, // 和WooCommerce默认Nonce有效期保持一致
    });
  }

  // 返回WooCommerce的响应结果
  const data = await wcResponse.json();
  return NextResponse.json(data, { status: wcResponse.status });
}

二、Nonce的高效管理

WooCommerce Store API会在所有GET请求的响应头返回X-WC-Store-API-Nonce,我们可以在服务端预渲染时获取并存储到Cookie,实现全局可用,同时自动更新。

1. 在服务端组件中获取并设置Nonce

修改你的Products服务端组件,在获取商品时提取Nonce并写入Cookie:

import { cookies } from 'next/headers';

async function getProducts() {
  const response = await fetch('https://my-example-store.local/wp-json/wc/store/v1/products');
  if (!response.ok) { throw new Error('获取商品数据失败'); }

  // 提取响应头中的Nonce
  const nonce = response.headers.get('X-WC-Store-API-Nonce');
  if (nonce) {
    const cookieStore = cookies();
    cookieStore.set('wc_store_api_nonce', nonce, {
      path: '/',
      sameSite: 'lax',
      httpOnly: false,
      maxAge: 3600,
    });
  }

  return response.json();
}

interface Product {
  id: number,
  name: string,
  sku: string,
}

const Products = async () => {
  const products: Product[] = await getProducts();
  return (
    <>
      {products.map(product => (
        <div key={product.sku}>
          <div>{product.name}</div>
          {/* 传入商品ID到客户端按钮组件 */}
          <Button id={product.id} variation="" />
        </div>
      ))}
    </>
  );
}

export default Products;

2. 客户端组件读取Nonce并调用代理API

修改你的Button客户端组件,调用自己的API路由完成加入购物车操作:

"use client";

async function addToCart({id, variation}: {id: number, variation:string}) {
  try {
    const response = await fetch('/api/cart/add-item', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        id,
        variation_id: variation ? parseInt(variation) : undefined,
      }),
    });

    if (!response.ok) {
      const errorData = await response.json();
      // 处理Nonce过期:403状态码代表Nonce失效
      if (response.status === 403) {
        alert('会话过期,请刷新页面后重试');
        // 可选:自动触发页面刷新获取新Nonce
        // window.location.reload();
      } else {
        throw new Error(errorData.error || '加入购物车失败');
      }
    }

    const data = await response.json();
    console.log('加入购物车成功:', data);
  } catch (err) {
    console.error('加入购物车失败:', err);
    alert('加入购物车失败,请稍后重试');
  }
}

export default function Button({ id, variation }: { id: number, variation: string }) {
  const handleEvent = async () => {
    await addToCart({id, variation});
  };

  return (
    <button onClick={handleEvent}>加入购物车</button>
  );
}

三、最佳实践总结

  • 代理优先:永远通过Next.js API路由中转客户端的修改类请求,既规避CORS,也避免直接暴露WooCommerce域名带来的安全风险。
  • Cookie存储Nonce:利用服务端组件的Cookie操作能力,将Nonce全局存储,客户端无需额外状态管理,且能自动更新。
  • 过期处理:监听403响应,提示用户刷新页面或自动触发新Nonce的获取,保证流程顺畅。
  • 避免HttpOnly:因为客户端需要读取Nonce(即使通过代理,后续扩展场景可能用到),所以Cookie不要设置HttpOnly属性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 10:42:03