's'
This commit is contained in:
@@ -8,7 +8,7 @@ ZPAY、PocketBase、MinIO 配置与 `C:\project\digital` 保持一致,复制 `
|
|||||||
|
|
||||||
| 变量 | 说明 | 默认值 |
|
| 变量 | 说明 | 默认值 |
|
||||||
|------|------|--------|
|
|------|------|--------|
|
||||||
| `NEXT_SERVER_ACTIONS_ENCRYPTION_KEY` | Server Actions 加密密钥(**生产部署必设**,避免 "Failed to find Server Action") | 无,需用 `node scripts/generate-encryption-key.js` 生成 |
|
| `NEXT_SERVER_ACTIONS_ENCRYPTION_KEY` | Server Actions 加密密钥(可选,未设时自动从 `config/server-actions.key` 加载) | `config/server-actions.key` |
|
||||||
| `NEXT_PUBLIC_POCKETBASE_URL` | PocketBase 地址 | `https://pocketbase.hackrobot.cn` |
|
| `NEXT_PUBLIC_POCKETBASE_URL` | PocketBase 地址 | `https://pocketbase.hackrobot.cn` |
|
||||||
| `NEXT_PUBLIC_API_URL` / `PAYMENT_API_URL` | payjsapi 地址 | `https://api.hackrobot.cn` |
|
| `NEXT_PUBLIC_API_URL` / `PAYMENT_API_URL` | payjsapi 地址 | `https://api.hackrobot.cn` |
|
||||||
| `PAYMENT_PROVIDER` | 支付提供商(payjsapi 环境变量) | `xorpay` / `zpay` |
|
| `PAYMENT_PROVIDER` | 支付提供商(payjsapi 环境变量) | `xorpay` / `zpay` |
|
||||||
|
|||||||
12
app/page.tsx
12
app/page.tsx
@@ -424,6 +424,12 @@ export default function Home() {
|
|||||||
}
|
}
|
||||||
}, [paidType]);
|
}, [paidType]);
|
||||||
|
|
||||||
|
const handleLogout = useCallback(async () => {
|
||||||
|
const { pbLogout } = await import("@/app/lib/pocketbase");
|
||||||
|
await pbLogout();
|
||||||
|
clearAllStorage();
|
||||||
|
}, [clearAllStorage]);
|
||||||
|
|
||||||
const isLoggedIn = paidType === "vip";
|
const isLoggedIn = paidType === "vip";
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
@@ -435,12 +441,6 @@ export default function Home() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleLogout = useCallback(async () => {
|
|
||||||
const { pbLogout } = await import("@/app/lib/pocketbase");
|
|
||||||
await pbLogout();
|
|
||||||
clearAllStorage();
|
|
||||||
}, [clearAllStorage]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<VipLayout isLoggedIn={isLoggedIn} userName={userName} onLogout={handleLogout}>
|
<VipLayout isLoggedIn={isLoggedIn} userName={userName} onLogout={handleLogout}>
|
||||||
|
|||||||
1
config/server-actions.key
Normal file
1
config/server-actions.key
Normal file
@@ -0,0 +1 @@
|
|||||||
|
hF2KLr00cW2L1KqktKFzzOiwcSS1D/b4zEkhuMWAsQs=
|
||||||
@@ -10,37 +10,9 @@ Error: Failed to find Server Action. This request might be from an older or newe
|
|||||||
|
|
||||||
**原因**:Next.js 为 Server Actions 使用加密密钥,每次构建会重新生成。部署后客户端可能仍缓存旧版本 JS,导致请求的 action ID 与服务器不匹配。
|
**原因**:Next.js 为 Server Actions 使用加密密钥,每次构建会重新生成。部署后客户端可能仍缓存旧版本 JS,导致请求的 action ID 与服务器不匹配。
|
||||||
|
|
||||||
**解决方案**:在**构建时**设置固定加密密钥 `NEXT_SERVER_ACTIONS_ENCRYPTION_KEY`,使多次部署使用相同密钥。
|
**解决方案**:项目已内置 `config/server-actions.key`,构建时 `next.config.ts` 会自动加载,无需手动配置。直接执行 `pnpm build` 即可。
|
||||||
|
|
||||||
### 步骤
|
部署后若仍有问题,可让用户执行硬刷新(Ctrl+Shift+R)或清除浏览器缓存。
|
||||||
|
|
||||||
1. **生成密钥**(仅需执行一次,之后复用同一密钥):
|
|
||||||
|
|
||||||
```bash
|
|
||||||
node scripts/generate-encryption-key.js
|
|
||||||
```
|
|
||||||
|
|
||||||
2. **在构建前设置环境变量**:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
export NEXT_SERVER_ACTIONS_ENCRYPTION_KEY="<上一步输出的 base64 字符串>"
|
|
||||||
pnpm build
|
|
||||||
```
|
|
||||||
|
|
||||||
或在 `.env` / `.env.production` 中添加:
|
|
||||||
|
|
||||||
```
|
|
||||||
NEXT_SERVER_ACTIONS_ENCRYPTION_KEY=<base64 字符串>
|
|
||||||
```
|
|
||||||
|
|
||||||
3. **重新构建并重启**:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
pnpm build
|
|
||||||
pm2 restart vip
|
|
||||||
```
|
|
||||||
|
|
||||||
4. **建议用户清除缓存**:部署后若仍有问题,可让用户执行硬刷新(Ctrl+Shift+R)或清除浏览器缓存。
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -50,8 +22,7 @@ Error: Failed to find Server Action. This request might be from an older or newe
|
|||||||
# 1. 安装依赖
|
# 1. 安装依赖
|
||||||
pnpm install
|
pnpm install
|
||||||
|
|
||||||
# 2. 设置 NEXT_SERVER_ACTIONS_ENCRYPTION_KEY 后构建
|
# 2. 构建(自动加载 config/server-actions.key)
|
||||||
export NEXT_SERVER_ACTIONS_ENCRYPTION_KEY="你的密钥"
|
|
||||||
pnpm build
|
pnpm build
|
||||||
|
|
||||||
# 3. 启动
|
# 3. 启动
|
||||||
|
|||||||
@@ -1,4 +1,14 @@
|
|||||||
import type { NextConfig } from "next";
|
import type { NextConfig } from "next";
|
||||||
|
import { readFileSync, existsSync } from "fs";
|
||||||
|
import { join } from "path";
|
||||||
|
|
||||||
|
// 构建时自动加载 Server Actions 加密密钥,避免 "Failed to find Server Action" 部署错误
|
||||||
|
if (!process.env.NEXT_SERVER_ACTIONS_ENCRYPTION_KEY) {
|
||||||
|
const keyPath = join(__dirname, "config", "server-actions.key");
|
||||||
|
if (existsSync(keyPath)) {
|
||||||
|
process.env.NEXT_SERVER_ACTIONS_ENCRYPTION_KEY = readFileSync(keyPath, "utf8").trim();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const nextConfig: NextConfig = {
|
const nextConfig: NextConfig = {
|
||||||
// 局域网访问(如手机 192.168.x.x)时允许跨域请求 _next 资源
|
// 局域网访问(如手机 192.168.x.x)时允许跨域请求 _next 资源
|
||||||
|
|||||||
@@ -1,13 +0,0 @@
|
|||||||
#!/usr/bin/env node
|
|
||||||
/**
|
|
||||||
* 生成 Next.js Server Actions 加密密钥
|
|
||||||
* 用于解决 "Failed to find Server Action" 部署错误
|
|
||||||
*
|
|
||||||
* 用法: node scripts/generate-encryption-key.js
|
|
||||||
* 将输出的 base64 字符串设置为环境变量 NEXT_SERVER_ACTIONS_ENCRYPTION_KEY
|
|
||||||
* 在构建时设置(pnpm build 前 export 或 .env 中配置)
|
|
||||||
*/
|
|
||||||
const crypto = require("crypto");
|
|
||||||
const key = crypto.randomBytes(32).toString("base64");
|
|
||||||
console.log("将以下值设置为 NEXT_SERVER_ACTIONS_ENCRYPTION_KEY:\n");
|
|
||||||
console.log(key);
|
|
||||||
Reference in New Issue
Block a user