.Net Core 后台 + Apisix 网关 解决跨域访问Cors问题

1, 什么是跨域

浏览器从一个域名的网页去请求另一个域名的资源时,域名、端口、协议任一不同,都是跨域
域名:
 主域名不同 http://www.baidu.com/index.html -->http://www.sina.com/test.js
 子域名不同 http://www.666.baidu.com/index.html -->http://www.555.baidu.com/test.js
 域名和域名ip http://www.baidu.com/index.html -->http://180.149.132.47/test.js
端口:
 http://www.baidu.com:8080/index.html–> http://www.baidu.com:8081/test.js
协议:
 http://www.baidu.com:8080/index.html–> https://www.baidu.com:8080/test.js
备注:
 1、端口和协议的不同,只能通过后台来解决
 2、localhost和127.0.0.1虽然都指向本机,但也属于跨域

当发生跨域访问(cross-domain access),浏览器就无法正常从后台服务中获取信息。所以必须要解决跨域问题。

 

2,跨域的种类

浏览器将CORS请求分成两类:简单请求(simple request)非简单请求(not-so-simple request)。

只要同时满足以下两大条件,就属于简单请求。

1) 请求方法是以下三种方法之一:

HEAD
GET
POST

(2)HTTP的头信息不超出以下几种字段:

Accept
Accept-Language
Content-Language
Last-Event-ID
Content-Type:只限于三个值 
    application/x-www-form-urlencoded(对发送内容进行编码)
    multipart/form-data(上传的表单内包含文件)
    text/plain(发送内容为纯文本格式)

凡是不同时满足上面两个条件,就属于非简单请求。

 

对于简单请求,浏览器直接发出CORS请求。具体来说,就是在头信息之中,增加一个Origin字段。

Origin: http://api.bob.com
Host: api.alice.com
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0

上面的头信息中,Origin字段用来说明,本次请求来自哪个源(协议 + 域名 + 端口)。服务器根据这个值,再根据自身的跨域设置,决定是否同意这次请求。

如果Origin指定的源,不在许可范围内,服务器会返回一个正常的HTTP回应。浏览器发现,这个回应的头信息没有包含Access-Control-Allow-Origin字段(详见下文),就知道出错了,从而抛出一个错误,被XMLHttpRequestonerror回调函数捕获。注意,这种错误无法通过状态码识别,因为HTTP回应的状态码有可能是200。

 

对于非简单请求的CORS请求,会在正式通信之前,不需要用户操作,浏览器自动发送一个OPTION请求(也叫做预检操作)。

服务器收到预检请求后,检查这些特殊的请求方法和头自己能否接受。如果服务器支持预检中的Header和Methods,那么接下来就可以正常发送信息。

 

3,跨域的解决方案

跨域问题可以从三个方面着手解决:前端/后端/网关

前端很多的解决方案,例如Vue的话可以试试:axios解决跨域问题(vue-cli3.0)

.Net Core 3.1 的后端的解决方法也比较简单,最懒的方法是在Startup.cs的Configure方法增加以下代码:

   app.UseCors(builder =>
            {
                builder.AllowAnyMethod()
                    .AllowAnyHeader()
                    .SetIsOriginAllowed(_ => true) // =AllowAnyOrigin()
                    .AllowCredentials();
            });

将上述代码插入到 app.UseRouting() 与 app.UseCors之间,则在全局范围内取消了一切跨域访问的限制。

或者,在ConfigureServices方法添加跨域设置,然后在Configure方法使用这个跨域设置也可以:

//ConfigureServices 设置允许所有来源跨域
            services.AddCors(options => options.AddPolicy("CorsPolicy",
            builder =>
            {
                builder.AllowAnyMethod()
                    .AllowAnyHeader()
                    .SetIsOriginAllowed(_ => true) // =AllowAnyOrigin()
                    .AllowCredentials();
            }));



//Configure 使用跨域配置
            app.UseCors("CorsPolicy");

 

如果不想全局都一个跨域的设置,而是每一个Controller设置每一个方法都有特定的跨域设置,则可以在Startup.cs文件的方法用AddCors方法添加若干个跨域设置,然后在对应的Controller或者方法上使用 [EnableCors] 属性启用 CORS。

详情可以参考微软官方文档:在 ASP.NET Core 中启用跨源请求 (CORS)

 

对于后台服务来说,一般都要配备网关。我这个项目选用了国人开源的Apisix网关。Apisix的使用就不啰嗦了,反正友好的文档以及方便的Dashboard,相当的不错。

前面说过,跨域请求的“非简单请求”会首先发送一次OPTION请求(预检操作)到服务器,等待服务器告知正常才正式执行请求。所以,务必务必,在网关设置允许的HTTP方法里,添加选择OPTION

 

 如果后端已经开启了CORS,则网关除了HTTP方法外无需留意其他的设置。但如果后端不设置的话,网关也一样能解决跨域访问

我们在Apisix网关的路由配置页面的第三步“插件配置”里可以发现一个Cors,只需要将其启用即可:

 

 相关的配置,Apisix也有详细的文档说明:cors

 

 

 

4,参考链接:

什么是跨域?如何解决跨域问题?

CORS简单请求和非简单请求

CORS请求的简单请求和非简单请求

 

posted @ 2022-02-18 18:22  AlvinLiang  阅读(1960)  评论(0编辑  收藏  举报