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

AWS CloudFront+S3前端访问EC2 Node服务出现CORS错误如何解决

技术栈

  • Client: React, Redux, axios
  • Server: AWS-EC2, Route 53, S3, CloudFront, NodeJS, express

第一步,我在Route 53购买了域名,已完成ACM证书签发。
第二步,我将前端构建文件上传到S3存储桶,配置为静态网站。
第三步,将Route 53域名和S3存储桶关联到CloudFront。
第四步,为EC2配置了ELB负载均衡和弹性公网IP(EIP)。
第五步,EC2上部署了Node.js express服务。
第六步,在CloudFront配置了重定向规则:将S3的www.domain.link 请求重定向到 domain.link。

存在问题的客户端和服务端代码如下:

Client.js

import axios from "axios";
import { TYPES, MAF } from "./types";
const API_AUTH = "https://www.domain.link/auth";
const API_USER = "https://www.domain.link";
//必填!!
axios.defaults.withCredentials = true;

export function loggedIn(data) {
  return (dispatch) => {
    axios.post(`${API_AUTH}/login`, data).then((res) => {
      console.log(res);
      dispatch({
        type: TYPES.LOGIN_SUCCESS,
        // payload: res.data.userData,
      });

      dispatch({
        type: MAF.HIDE_MODAL,
      });
    });
  };
}

export function register(data) {
  return (dispatch) => {
    axios.post(`${API_AUTH}/register`, data).then((res) => {
      dispatch({
        type: TYPES.REGISTER_SUCCESS,
        payload: res.data,
      });
    });
  };
}

./routes/user.js

const router = require("express").Router();

const {
  login,
  register,
  logout,
  profile,
} = require("../controller/userController/userController");
const { authorization } = require("../config/JWTConfig");

router.post("/auth/login", login);
router.post("/auth/register", register);
router.get("/auth/logout", authorization, logout);
router.get("/auth/profile", authorization, profile);

module.exports = router;

./app.js

const express = require("express");
// const passportConfig = require("./passport/index");
const passport = require("passport");
const http = require("http");
const https = require("https");
const path = require("path");
const fs = require("fs");
const cors = require("cors");
const cookieParser = require("cookie-parser");
const logger = require("morgan");

require("dotenv").config();
const authRoute = require("./routes/users");
const mainRoute = require("./routes/main");
const port = process.env.PORT || 3000;
const app = express();

const whitelist = [
  "http://localhost:3000",
  "http://*.doamin.link",
  "http://doamin.link",
  "http://doamin.link/*",
];
const corsOption = {
  origin: function (origin, callback) {
    if (whitelist.indexOf(origin) !== -1 || !origin) {
      callback(null, true);
    } else {
      callback(new Error("Not allowed by CORS"));
    }
  },
  credentials: true,
  methods: ["GET", "POST", "PUT", "DELETE", "OPTION"],
};

app.use(cookieParser());

app.use(logger("dev"));

app.use(cors(corsOption));
app.use(express.urlencoded({ extended: false }));
app.use(express.json());

app.use(mainRoute);
app.use(authRoute);

let server;

if (fs.existsSync("./cert/key.pem") && fs.existsSync("./cert/cert.pem")) {
  const privateKey = fs.readFileSync(__dirname + "/cert/key.pem", "utf8");
  const certificate = fs.readFileSync(__dirname + "/cert/cert.pem", "utf8");
  const credentials = { key: privateKey, cert: certificate };

  server = https.createServer(credentials, app);
  server.listen(port, () => console.log("https server Running"));
} else {
  server = app.listen(port, () => {
    console.log(`http server Running`);
  });
}

module.exports = server;

在Postman测试或者浏览器点击登录按钮时,会出现如下错误:

Access to XMLHttpRequest at 'https://www.domain.link/login' 
from origin 'https://domain.link' has been blocked by CORS policy: 
Response to preflight request doesn't pass access control check:
 No 'Access-Control-Allow-Origin' header is present on the requested resource.
createError.js:16 Uncaught (in promise) Error: Network Error
    at e.exports (createError.js:16)
    at XMLHttpRequest.p.onerror (xhr.js:84)

访问domain.link、www.domain.link 都会触发上述错误。

Postman测试截图

Postman测试截图


修复方案

1. 修复服务端CORS配置错误

你现有CORS配置存在4个问题:

  • 域名拼写错误:doamin.link应为domain.link
  • 协议不匹配:网站已启用HTTPS,但白名单写的是HTTP开头的域名
  • 预检方法拼写错误:OPTION应为OPTIONS
  • cors包不支持直接用*.domain.link这种通配符匹配规则

将app.js的CORS配置替换为如下内容:

const whitelist = [
  "http://localhost:3000",
  "https://domain.link",
  "https://www.domain.link"
];
const corsOption = {
  origin: function (origin, callback) {
    if (whitelist.includes(origin) || !origin) {
      callback(null, true);
    } else {
      callback(null, false);
    }
  },
  credentials: true,
  methods: ["GET", "POST", "PUT", "DELETE", "OPTIONS"],
  allowedHeaders: ["Content-Type", "Authorization"]
};
// 单独处理所有预检请求
app.options('*', cors(corsOption));

2. 修正API请求路由

你当前前端API请求直接打到了前端对应的CloudFront/S3地址,根本没有转发到EC2服务,二选一选择以下方案:

  • 方案1:单独配置api.domain.link二级域名解析到EC2的ELB,前端API_BASE修改为https://api.domain.link
  • 方案2:在CloudFront新增行为,路径规则设置为/auth/*,源站选择EC2对应的ELB,允许GET、POST、OPTIONS方法,配置转发Origin、Access-Control-Request-Headers、Access-Control-Request-Method头,禁用该路径的缓存

3. 修复前端API地址

配合上面的路由配置,将Client.js的API地址修改为同源路径(适配方案2)或者新的API二级域名(适配方案1):

// 适配CloudFront路径转发,直接用同源路径避免跨域
const API_AUTH = "/auth";
const API_USER = "/";

4. 验证CloudFront配置

  • 确认仅前端静态资源路径配置了www到根域名的重定向,API路径不会被重定向
  • 确认ACM证书覆盖了所有用到的域名
  • 确认CloudFront对应API路径的行为没有缓存预检请求

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.07 04:09:03