Node.js/Express中POST请求CORS正常,GET请求CORS异常求助
问题场景
我用JavaScript的fetch方法从Node.js/Express服务器获取静态HTML文件,代码如下:
const response = await fetch(url); const data = await response.text();
每次都会触发CORS错误:
"Access to fetch at 'https://rez-dev.workbest.de/rezept_camera_grid.html' from origin 'https://docproeller.de' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled."
通过测试发现:
- GET方式请求静态文件时CORS验证失败
- POST请求能正常通过CORS验证
服务器代码已经引入并使用了cors中间件,但问题依然存在,服务器代码片段如下:
const express = require("express"); const https = require("https"); const http = require("http"); const cors = require("cors"); // Use static files app.use(express.static('public')); // Use json- and url-encoding app.use(express.json()); app.use(express.urlencoded({extended:true})); // Use CORS // Allow all Origins app.use(cors()); https_port=443; sslServer = https.createServer({ key: fs.readFileSync(path.join(ssl_server_key)), cert: fs.readFileSync(path.join(ssl_server_cert)) }, app); sslServer.listen(https_port, () => console.log("Secure Server is listening on port " + sslServer.address().port));
问题根源
中间件执行顺序错误:你把express.static静态文件中间件放在了cors()中间件前面。Express的中间件是按代码书写顺序依次执行的,静态文件请求会被express.static直接处理并返回响应,根本不会走到后面的cors()中间件,所以静态资源的响应头里没有Access-Control-Allow-Origin字段,导致GET请求(静态文件默认请求方法)触发CORS错误。而POST请求不属于静态文件请求范畴,会正常经过cors()中间件处理,因此能通过CORS验证。
解决方案
调整中间件加载顺序,把cors()放在express.static之前,确保所有请求(包括静态文件请求)都先经过CORS中间件处理:
修正后的服务器代码:
const express = require("express"); const https = require("https"); const http = require("http"); const cors = require("cors"); const fs = require("fs"); // 补充原代码遗漏的模块引入 const path = require("path"); // 补充原代码遗漏的模块引入 // 先加载CORS中间件,覆盖所有请求 app.use(cors()); // 再加载静态文件中间件 app.use(express.static('public')); // 其他解析中间件 app.use(express.json()); app.use(express.urlencoded({extended:true})); https_port=443; sslServer = https.createServer({ key: fs.readFileSync(path.join(ssl_server_key)), cert: fs.readFileSync(path.join(ssl_server_cert)) }, app); sslServer.listen(https_port, () => console.log("Secure Server is listening on port " + sslServer.address().port));
额外提示
- 原代码中使用了
fs和path模块但未引入,运行时会报错,记得补充require语句。 - 如果需要限制访问源,可给
cors()传入配置对象,比如只允许指定域名访问:
app.use(cors({ origin: 'https://docproeller.de' // 仅允许该域名发起跨域请求 }));
内容的提问来源于stack exchange,提问作者Jörg

