为Node.js Serverless Lambda函数添加CORS标头的配置问题
问题背景
首次基于AWS服务+Serverless框架开发应用时,接口请求抛出跨域错误:No 'Access-Control-Allow-Origin' header is present on the requested resource,排查过程受阻。
已在serverless.yml中为Lambda函数配置了API Gateway层面的CORS规则:
- http: method: ANY path: /{proxy+} cors: origin: "*" headers: "*"
查阅资料后得知还需要在函数代码层面添加CORS响应头,当前项目代码结构如下:
Lambda入口handler代码:
const routes = require("./routes"); const server = awsServerlessExpress.createServer(routes); exports.handler = (event, context) => awsServerlessExpress.proxy(server, event, context);
业务路由示例(登录接口):
module.exports = async (req, res) => { try { const { email, password } = req.body; const params = { AuthFlow: "ADMIN_NO_SRP_AUTH", UserPoolId: userPoolId, ClientId: clientId, AuthParameters: { USERNAME: email, PASSWORD: password, }, }; const userIsValidated = await cognito.adminInitiateAuth(params).promise(); res.send({ message: "Success", token: userIsValidated.AuthenticationResult.IdToken, }); } catch (error) { const message = error.message ? error.message : "Internal server error"; res.send({ message }); } };
当前排查卡点有两个:
- 直接在Lambda handler层添加响应头会破坏
awsServerlessExpress原有代理逻辑 - 逐个在业务路由函数中添加CORS头重复度高,无法实现所有接口自动携带标头
解决方案
当前项目用aws-serverless-express把Express服务跑在Lambda上,不需要修改Lambda入口代码,也不用逐个路由加头,直接在Express层配置全局CORS中间件即可,侵入性最低、维护成本最小。
- 安装CORS依赖
执行命令安装Express生态通用的cors中间件:npm install cors - 注册全局中间件
打开handler.js中引入的./routes对应的文件(通常是Express实例初始化的app.js/index.js),在所有路由注册之前挂载cors中间件:const express = require('express'); const cors = require('cors'); const app = express(); // 全局CORS配置,所有接口响应自动携带跨域头 app.use(cors({ origin: "*", allowedHeaders: "*" })); // 原有路由注册逻辑保持不变 // app.use('/login', require('./routes/login')) module.exports = app; - 补充说明
- 注意:
serverless.yml中配置的cors规则仅作用于API Gateway层,负责自动响应OPTIONS预检请求,不会主动给业务接口的响应添加CORS头,必须和应用层的CORS配置保持一致才能彻底解决跨域报错。 - 如果不想引入第三方依赖,也可以手写极简全局CORS中间件,效果一致:
// 放在所有路由注册之前 app.use((req, res, next) => { res.setHeader('Access-Control-Allow-Origin', '*'); res.setHeader('Access-Control-Allow-Headers', '*'); res.setHeader('Access-Control-Allow-Methods', 'GET,POST,PUT,DELETE,OPTIONS'); // 预检请求直接返回200,不需要转发到业务逻辑 if (req.method === 'OPTIONS') return res.sendStatus(200); next(); }); - 修改完成后必须重新执行
serverless deploy部署到AWS,本地修改未部署不会生效。
- 注意:
内容的提问来源于stack exchange,提问作者Joaquin Kaplan
相关产品推荐
相关产品推荐

