Express 中 CORS 跨域问题解决教程

一、CORS 核心概念

1. 同源策略

同源指的是 协议、域名、端口 三者完全一致。例如:

  • 前端地址:http://localhost:3000
  • 后端地址:http://localhost:8080
    由于端口不同,属于不同源,前端请求后端接口时会被浏览器拦截。

2. 跨域请求分类

  • 简单请求:满足以下条件的请求为简单请求

    1. 请求方法为 GET/HEAD/POST
    2. 请求头仅包含 Accept/Accept-Language/Content-Language/Content-Type(值仅限 application/x-www-form-urlencoded/multipart/form-data/text/plain
      简单请求会直接发送,浏览器在响应头中检查 Access-Control-Allow-Origin 字段判断是否允许跨域。
  • 复杂请求 :不满足简单请求条件的请求(如 PUT/DELETE 方法、自定义请求头)

    复杂请求会先发送 OPTIONS 预检请求,询问后端是否允许该跨域请求,预检通过后才会发送真实请求。

二、安装 cors 中间件

cors 是 Express 的官方推荐跨域处理中间件,通过 npm 安装:

bash 复制代码
npm install cors

三、基础使用方案

1. 允许所有来源跨域(开发环境常用)

这是最简便的配置,直接启用 cors 中间件,允许所有域名访问后端接口:

javascript 复制代码
var express = require('express')
var cors = require('cors')
var app = express()

// 全局启用 CORS,允许所有 origin
app.use(cors())

app.get('/api/data', (req, res) => {
  res.json({ message: 'This is CORS-enabled for all origins!' })
})

app.listen(8080, () => {
  console.log('Server running on port 8080')
})

适用场景:本地开发环境,无需限制访问来源。

2. 仅允许单个路由跨域

如果不需要全局跨域,可针对特定路由单独启用 cors

javascript 复制代码
var express = require('express')
var cors = require('cors')
var app = express()

// 仅 /api/products 路由允许跨域
app.get('/api/products/:id', cors(), (req, res) => {
  res.json({ message: 'This is CORS-enabled for a Single Route' })
})

// 其他路由不允许跨域
app.get('/api/user', (req, res) => {
  res.json({ message: 'No CORS for this route' })
})

app.listen(8080)

四、高级配置方案

1. 限制指定来源跨域(生产环境常用)

生产环境中,需要严格限制允许跨域的前端域名,避免恶意请求:

javascript 复制代码
var express = require('express')
var cors = require('cors')
var app = express()

// 配置跨域选项
var corsOptions = {
  // 仅允许 http://example.com 访问
  origin: 'http://example.com',
  // 兼容 IE11 等老旧浏览器(避免 204 状态码报错)
  optionsSuccessStatus: 200
}

// 全局启用带配置的 CORS
app.use(cors(corsOptions))

app.get('/api/data', (req, res) => {
  res.json({ message: 'Only example.com can access this!' })
})

app.listen(8080)

2. 动态白名单跨域

如果需要允许多个域名访问,可配置白名单,通过函数动态判断请求来源是否合法:

javascript 复制代码
var express = require('express')
var cors = require('cors')
var app = express()

// 跨域白名单
var whitelist = ['http://example1.com', 'http://example2.com', 'http://localhost:3000']

var corsOptions = {
  origin: function (origin, callback) {
    // 白名单内的 origin 或无 origin(如 Postman 等工具请求)允许跨域
    if (whitelist.indexOf(origin) !== -1 || !origin) {
      callback(null, true)
    } else {
      callback(new Error('Not allowed by CORS'))
    }
  }
}

app.use(cors(corsOptions))

app.get('/api/data', (req, res) => {
  res.json({ message: 'Only whitelisted domains can access!' })
})

app.listen(8080)

关键说明!origin 用于兼容 Postman、curl 等无浏览器环境的工具请求,避免这些工具被误判为跨域。

3. 处理复杂请求的预检(OPTIONS)

对于 PUT/DELETE 等复杂请求,需要手动配置 OPTIONS 预检请求的处理:

javascript 复制代码
var express = require('express')
var cors = require('cors')
var app = express()

// 全局处理所有路由的 OPTIONS 预检请求
app.options('*', cors())

// DELETE 方法属于复杂请求,需预检
app.delete('/api/data/:id', cors(), (req, res) => {
  res.json({ message: 'DELETE request is CORS-enabled!' })
})

app.listen(8080)

核心原理app.options('*', cors()) 会拦截所有 OPTIONS 预检请求,返回跨域允许的响应头,确保后续真实请求能正常发送。

4. 异步配置跨域

如果需要从数据库或配置文件中动态获取白名单,可使用异步配置:

javascript 复制代码
var express = require('express')
var cors = require('cors')
var app = express()

// 模拟从数据库获取白名单
function getWhitelistFromDB() {
  return Promise.resolve(['http://example1.com', 'http://example2.com'])
}

// 异步跨域配置
var corsOptionsDelegate = async function (req, callback) {
  var whitelist = await getWhitelistFromDB()
  var corsOptions = { origin: false }

  if (whitelist.indexOf(req.header('Origin')) !== -1) {
    corsOptions.origin = true
  }

  callback(null, corsOptions)
}

app.get('/api/data', cors(corsOptionsDelegate), (req, res) => {
  res.json({ message: 'Async CORS configuration!' })
})

app.listen(8080)

五、完整配置选项说明

cors 中间件支持丰富的配置项,覆盖所有 CORS 响应头需求:

配置项 类型 作用 示例
origin String/RegExp/Array/Function 配置允许的跨域来源 origin: 'http://example.com'
methods String/Array 配置允许的请求方法 methods: ['GET', 'POST', 'PUT']
allowedHeaders String/Array 配置允许的请求头 allowedHeaders: ['Content-Type', 'Authorization']
exposedHeaders String/Array 配置前端可访问的响应头 exposedHeaders: ['X-Total-Count']
credentials Boolean 是否允许携带 Cookie credentials: true
maxAge Number 预检请求的缓存时间(秒) maxAge: 86400(缓存 24 小时)
preflightContinue Boolean 是否将预检请求传递给下一个中间件 preflightContinue: false
optionsSuccessStatus Number 预检请求成功的状态码 optionsSuccessStatus: 200

如果前端需要在跨域请求中携带 Cookie(如身份认证),需同时配置前后端:

  • 后端配置

    javascript 复制代码
    var corsOptions = {
      origin: 'http://example.com',
      credentials: true // 允许跨域携带 Cookie
    }
    app.use(cors(corsOptions))
  • 前端配置(Axios 示例)

    javascript 复制代码
    axios.get('http://localhost:8080/api/data', {
      withCredentials: true // 携带 Cookie
    })

六、常见问题与解决方案

  1. 问题 :配置后仍然跨域报错
    原因 :可能是复杂请求未处理 OPTIONS 预检,或 origin 配置错误。
    解决方案 :添加 app.options('*', cors()),检查白名单是否包含前端真实域名。

  2. 问题 :IE11 浏览器跨域请求失败
    原因 :IE11 不兼容 204 状态码。
    解决方案 :配置 optionsSuccessStatus: 200

  3. 问题 :携带 Cookie 时跨域失败
    原因credentials 未开启,或 origin 配置为 *(不能同时使用 *credentials: true)。
    解决方案origin 配置为具体域名,同时开启 credentials: true

七、总结

cors 中间件是 Express 处理跨域的高效工具,核心配置思路为:

  • 开发环境 :使用 app.use(cors()) 允许所有来源。
  • 生产环境:配置白名单限制来源,处理复杂请求的预检,必要时开启 Cookie 支持。

合理配置 CORS 既能保证前后端通信正常,又能提升接口的安全性

相关推荐
GDAL2 小时前
express.text和fetch配合使用深入全面教程
express·text
GDAL1 天前
Express POST 请求深入全面讲解教程
express
正经教主2 天前
【Trae+AI】和Trae学习搭建App_2.1:第3章·手搓后端基础框架Express
人工智能·后端·学习·express
这是个栗子3 天前
【前端知识点总结】前端跨域问题
前端·跨域·cors
闲人编程4 天前
CORS跨域配置与安全策略
中间件·origin·跨域·cors·codecapsule·分离配置·最小权限
你真的可爱呀5 天前
2.Express 核心语法与路由
中间件·node.js·express
骚团长5 天前
SQL server 配置管理器-SQL server 服务-远程过程调试失败 [0x800706be]-(Express LocalDB卸载掉)完美解决!
java·服务器·express
你真的可爱呀6 天前
1.基础环境搭建与核心认知
node.js·express
你真的可爱呀6 天前
3.MySQL 数据库集成
mysql·node.js·express