服务器跨域问题CORS的解决

制作大屏过程中,通过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 方法的预检请求,用来询问:

  1. 询问服务器是否允许当前源的跨域请求
  2. 询问服务器支持哪些 HTTP 方法和请求头

只有当服务器正确响应并允许后,浏览器才会发送真正的业务请求(比如 GET/POST)。

代码中if (Request.HttpMethod == "OPTIONS")的逻辑是:

  • 如果检测到是预检请求(OPTIONS 方法)
  • 直接返回 200 状态码(表示允许)
  • 不需要返回业务数据,直接结束响应

这样浏览器就会认为 "服务器允许跨域",进而发送真正的业务请求。如果没有这段处理,服务器可能会对 OPTIONS 请求返回 404 或其他错误状态,导致浏览器阻断后续的实际请求,从而出现 CORS 错误。

3 AllowedCorsHeaders是否只是针对跨域的进行限制

确实是专门针对跨域请求的请求头限制,它的作用是告诉浏览器:"服务器允许前端跨域请求中携带哪些自定义头信息"。

  1. 它只限制跨域请求中前端携带的头信息,对同域请求(前端和后端在同一域名 / 端口)没有任何影响。
  2. 不需要也不应该添加所有可能的头,而是按需添加。如果开发阶段不确定需要哪些头,或头信息频繁变化,可临时用通配符允许所有头(不推荐生产环境):
csharp 复制代码
Response.Headers.Add("Access-Control-Allow-Headers", "*")
  1. 如果缺少必要的头配置,会出现类似以下错误, 此时只需将 X-Token 添加到 AllowedCorsHeaders 即可解决。
bash 复制代码
Request header field X-Token is not allowed by Access-Control-Allow-Headers in preflight response.

解决办法

最终的解决办法是在 .NET 项目中实现跨域源的动态化,核心是避免将域名硬编码在代码里。

  1. 第一步:在 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>
  1. 第二步:在 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();
    }
}
相关推荐
小白银子2 小时前
零基础从头教学Linux(Day 42)
linux·运维·服务器·网络·nginx
DDC楼宇自控与IBMS集成系统解读3 小时前
园区3D可视化数字孪生管理平台与 IBMS 智能化集成系统:打造智慧园区新范式
运维·3d可视化·楼宇自控系统·数字孪生管理平台·ibms集成系统·3d可视化数字孪生管理平台·智能化集成系统
望获linux3 小时前
【Linux基础知识系列:第一百四十篇】理解SELinux与系统安全
linux·运维·服务器·数据库·chrome·macos
初学者_xuan3 小时前
零基础新手小白快速了解掌握服务集群与自动化运维(七)Nginx模块--Nginx反向代理与缓存功能(二)
运维·nginx·自动化
Java-xy²3 小时前
AlmaLinux release 9.6服务器离线安装MySQL8.0.27详细步骤
运维·服务器·adb
啦啦啦在冲冲冲3 小时前
如何计算sequence粒度的负载均衡损失
运维·负载均衡
zcz16071278213 小时前
Ansible Playbook
运维
人逝花落空.3 小时前
docker容器的三大核心技术UnionFS(下)
运维·docker·容器
岚天start3 小时前
Nginx配置中location和proxy_pass指令尾部是否带斜杠的区别
运维·nginx·centos·proxy_pass·location·uri·斜杠