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

Next.js集成Wasm脚本时遭遇CORS跨域问题求助

问题描述

尝试将已部署的Wasm应用迁移到Next.js路由,测试多种方案均失败,以下是最简复现示例:

Rust后端入口代码

use axum::Router;
use tower_http::services::{ServeDir, ServeFile};
use tower_http::cors::{Any, CorsLayer};

#[shuttle_runtime::main]
async fn main() -> shuttle_axum::ShuttleAxum {
    let layer = CorsLayer::new().allow_headers(Any);
    let router = Router::new().nest_service(
        "/",
        ServeDir::new("dist").not_found_service(ServeFile::new("dist/index.html")),
    ).layer(layer);
    Ok(router.into())
}

dist/index.html代码

<body>
    <canvas id="canvas" width="1280" height="720" cursor="auto"></canvas>
    <script crossorigin="anonymous" type="module">
        import init from "https://bevy-game.shuttleapp.rs/game.js"
        init()
    </script>
</body>

next.config.js配置

const getCorsHeaders = () => {
  const headers = {};

  headers["Access-Control-Allow-Origin"] = "*";
  headers["Access-Control-Allow-Credentials"] = "true";
  headers["Access-Control-Allow-Methods"] =
    "GET,OPTIONS,PATCH,DELETE,POST,PUT";
  headers["Access-Control-Allow-Headers"] =
    "X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, X-Api-Version, Authorization";

  return Object.entries(headers).map(([key, value]) => ({ key, value }));
};

/** @type {import('next').NextConfig} */
const nextConfig = {
  webpack(config) {
    config.module.rules.push({
      test: /\.svg$/i,
      use: ['@svgr/webpack'],
    })

    return config
  },
  async rewrites() {
    return [
      {
        source: '/wasm-test',
        destination: `https://prismatic-shortbread-d520b8.netlify.app`,
      },
      {
        source: '/wasm-test/:path*',
        destination: `https://prismatic-shortbread-d520b8.netlify.app/:path*`,
      },
      {
        source: '/wasm-shuttle',
        destination: `https://bevy-game.shuttleapp.rs`,
      },
      {
        source: '/wasm-shuttle/:path*',
        destination: `https://bevy-game.shuttleapp.rs/:path*`,
      }
    ]
  },
  headers: async () => {
    return [
      {
        source: "/wasm-test",
        headers: getCorsHeaders(),
      },
      {
        source: "/wasm-test/:path*",
        headers: getCorsHeaders(),
      },
      {
        source: "/wasm-shuttle",
        headers: getCorsHeaders(),
      },
      {
        source: "/wasm-shuttle/:path*",
        headers: getCorsHeaders(),
      },
    ];
  },
  ...
}

报错信息

wasm-shuttle:1 Access to script at 'https://bevy-game.shuttleapp.rs/game.js' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.


解决方案

1. 修复Rust后端的CORS配置

当前Axum的CORS层仅配置了允许任意请求头,但未设置允许的请求源,这是报错的核心原因。修改后端代码补充CORS规则:

use axum::Router;
use tower_http::services::{ServeDir, ServeFile};
use tower_http::cors::{Any, CorsLayer};

#[shuttle_runtime::main]
async fn main() -> shuttle_axum::ShuttleAxum {
    let layer = CorsLayer::new()
        .allow_headers(Any)
        .allow_origin(Any) // 开发环境允许所有源,生产环境需替换为具体域名
        .allow_methods(Any); // 补充允许所有请求方法
    let router = Router::new().nest_service(
        "/",
        ServeDir::new("dist").not_found_service(ServeFile::new("dist/index.html")),
    ).layer(layer);
    Ok(router.into())
}

生产环境建议指定具体允许的域名,示例:

.allow_origin(Origin::exact("http://localhost:3000").or(Origin::exact("你的生产域名")))

2. 调整Next.js中的脚本引入路径

利用已配置的rewrite规则,通过代理路径引入脚本,避免直接跨域请求:
修改dist/index.html中的脚本导入:

<script crossorigin="anonymous" type="module">
    import init from "/wasm-shuttle/game.js"
    init()
</script>

该请求会通过Next.js的rewrite转发到目标地址,从根源规避跨域问题。

3. 验证Next.js Headers配置

确保Headers规则正确匹配代理路径,若后端已修复CORS,此步骤可作为强化配置保留。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 07:23:20