制作大屏过程中,通过API连接服务器,出现如下错误:
Access to XMLHttpRequest at 'http://192.168.88.74:8089/Service/data/-3005?name=API' from origin 'http://localhost:3020' 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.
原因分析
这个错误是由于浏览器的 CORS(跨域资源共享)安全机制导致的。当你的前端应用(运行在http://localhost:3020)尝试访问不同源的后端 API(http://192.168.88.74:8089)时,浏览器会进行 CORS 检查。
要解决这个问题,需要在后端服务器的响应中添加适当的 CORS 头信息。具体来说,需要添加Access-Control-Allow-Origin头,指定允许访问的源。
处理过程
在 .NET 后端中添加 CORS 头,如果是传统的 ASP.NET 项目,可以在 Global.asax 中配置:
csharp
protected void Application_BeginRequest()
{
// 允许的源(生产环境建议指定具体域名,不要用*)
Response.Headers.Add("Access-Control-Allow-Origin", "http://localhost:3020");
// 允许的请求方法
Response.Headers.Add("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
// 允许的请求头
Response.Headers.Add("Access-Control-Allow-Headers", "Content-Type, Authorization");
// 处理预检请求
if (Request.HttpMethod == "OPTIONS")
{
Response.StatusCode = 200;
Response.End();
}
}
1 Response.Headers.Add后两句是否可以不要
这两句是否可以省略,取决于前端跨域请求的具体场景。如果前端只发送简单的 GET 请求(不包含自定义头信息、不携带凭据等),那么这两句可以省略。因为简单请求不会触发预检请求(OPTIONS),浏览器只会检查Access-Control-Allow-Origin头,只要这个头配置正确,简单请求就能正常工作。
如果前端有以下场景,必须保留这两句:
- 使用 POST/PUT/DELETE 等非 GET 方法
- 请求中包含自定义头信息(如 Authorization、Token 等)
- 发送 JSON 格式的 POST 请求(Content-Type: application/json)
这些情况会触发浏览器发送预检请求(OPTIONS),此时浏览器会检查:
- 服务器是否允许对应的请求方法(通过Access-Control-Allow-Methods)
- 服务器是否允许对应的请求头(通过Access-Control-Allow-Headers)
如果缺少这两个头,预检请求会失败,浏览器会阻断实际的业务请求。因此,即使当前只使用简单的 GET 请求,也建议保留这两句,因为:
- 未来可能会扩展使用其他请求方法或头信息
- 明确配置可以避免后续开发中出现意外的 CORS 错误
- 这两句配置对简单请求没有负面影响
所以最好的实践是保留这两个头的配置,确保兼容各种跨域请求场景。
2 预检请求是什么(OPTIONS 请求)
当浏览器判断一个跨域请求是 "复杂请求" 时(比如包含自定义头信息、使用 PUT/DELETE 等 HTTP 方法),会在真正发送请求之前,先发送一个OPTIONS 方法的预检请求,用来询问:
- 询问服务器是否允许当前源的跨域请求
- 询问服务器支持哪些 HTTP 方法和请求头
只有当服务器正确响应并允许后,浏览器才会发送真正的业务请求(比如 GET/POST)。
代码中if (Request.HttpMethod == "OPTIONS")的逻辑是:
- 如果检测到是预检请求(OPTIONS 方法)
- 直接返回 200 状态码(表示允许)
- 不需要返回业务数据,直接结束响应
这样浏览器就会认为 "服务器允许跨域",进而发送真正的业务请求。如果没有这段处理,服务器可能会对 OPTIONS 请求返回 404 或其他错误状态,导致浏览器阻断后续的实际请求,从而出现 CORS 错误。
3 AllowedCorsHeaders是否只是针对跨域的进行限制
确实是专门针对跨域请求的请求头限制,它的作用是告诉浏览器:"服务器允许前端跨域请求中携带哪些自定义头信息"。
- 它只限制跨域请求中前端携带的头信息,对同域请求(前端和后端在同一域名 / 端口)没有任何影响。
- 不需要也不应该添加所有可能的头,而是按需添加。如果开发阶段不确定需要哪些头,或头信息频繁变化,可临时用通配符允许所有头(不推荐生产环境):
csharp
Response.Headers.Add("Access-Control-Allow-Headers", "*")
- 如果缺少必要的头配置,会出现类似以下错误, 此时只需将 X-Token 添加到 AllowedCorsHeaders 即可解决。
bash
Request header field X-Token is not allowed by Access-Control-Allow-Headers in preflight response.
解决办法
最终的解决办法是在 .NET 项目中实现跨域源的动态化,核心是避免将域名硬编码在代码里。
- 第一步:在 web.config 中添加跨域源配置
在 < appSettings > 节点下新增配置项,支持多个源(用英文逗号分隔):
xml
<configuration>
<appSettings>
<!-- 动态配置允许的跨域源,多个源用逗号分隔 -->
<add key="AllowedCorsOrigins" value="http://localhost:3020,http://test.example.com,http://prod.example.com" />
<!-- 可选:配置允许的请求方法和头 -->
<add key="AllowedCorsMethods" value="GET,POST,PUT,DELETE,OPTIONS" />
<add key="AllowedCorsHeaders" value="Content-Type,Authorization" />
</appSettings>
</configuration>
- 第二步:在 Global.asax 中读取配置并应用
csharp
using System.Configuration; // 需引用 System.Configuration 程序集
protected void Application_BeginRequest()
{
// 1. 读取配置的跨域源(支持多个)
string allowedOrigins = ConfigurationManager.AppSettings["AllowedCorsOrigins"];
// 2. 读取当前请求的源(前端页面的域名)
string requestOrigin = Request.Headers.Get("Origin");
// 3. 验证当前请求源是否在允许列表中(避免直接返回 *,支持多源)
if (!string.IsNullOrEmpty(allowedOrigins) && !string.IsNullOrEmpty(requestOrigin))
{
var originList = allowedOrigins.Split(',');
if (originList.Contains(requestOrigin))
{
// 动态添加允许的源
Response.Headers.Add("Access-Control-Allow-Origin", requestOrigin);
// 动态添加允许的方法(从配置读取)
Response.Headers.Add("Access-Control-Allow-Methods", ConfigurationManager.AppSettings["AllowedCorsMethods"]);
// 动态添加允许的头(从配置读取)
Response.Headers.Add("Access-Control-Allow-Headers", ConfigurationManager.AppSettings["AllowedCorsHeaders"]);
// 支持凭据(如 Cookie,可选)
Response.Headers.Add("Access-Control-Allow-Credentials", "true");
}
}
// 4. 处理预检请求(OPTIONS)
if (Request.HttpMethod == "OPTIONS")
{
Response.StatusCode = 200;
Response.End();
}
}