.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
字段(详见下文),就知道出错了,从而抛出一个错误,被XMLHttpRequest
的onerror
回调函数捕获。注意,这种错误无法通过状态码识别,因为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,参考链接: