一、 介绍
为什么出现跨域问题?
源自浏览器的核心安全功能: 同源策略 , 即浏览器执行的 js 脚本不能请求其他域的资源。会影响资源的获取, Cookies 的读取, Ajax请求的发送。由服务器的后台请求就不会有跨域的问题。 所以可以使用 nginx 做反向代理,为浏览器暴露一个同域接口(跟前端同域不同路径)。
当然,也可以在服务端做限制 (主流)。
二、 判断条件
协议 、域名、 端口号, 任意一个不同即为跨域
如: http 和 https , book.alexljs.com 和 work.alexljs.com
三、 如何解决CORS?
1、 前端解决方案
a) JSONP
b) 一些不常用的原生方法
window.postMessage()
document.domain
2、 后台解决方案
a) nginx 做反向代理,后端和前端放在一个域中,如对外暴露 80 端口
b) 服务端配置 Access-Control-Allow-Origin 属性在 resp 的 header 中
四、举例 golang gin 的跨域解决方案
func CORS() gin.HandlerFunc {
return func(context *gin.Context) {
// 允许 Origin 字段中的域发送请求
context.Writer.Header().Add("Access-Control-Allow-Origin", *)
// 设置预验请求有效期为 86400 秒
context.Writer.Header().Set("Access-Control-Max-Age", "86400")
// 设置允许请求的方法
context.Writer.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE, UPDATE, PATCH")
// 设置允许请求的 Header
context.Writer.Header().Set("Access-Control-Allow-Headers", "Content-Type, Content-Length,Apitoken")
// 设置拿到除基本字段外的其他字段,如上面的Apitoken, 这里通过引用Access-Control-Expose-Headers,进行配置,效果是一样的。
context.Writer.Header().Set("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Headers")
// 配置是否可以带认证信息
context.Writer.Header().Set("Access-Control-Allow-Credentials", "true")
// OPTIONS请求返回200
if context.Request.Method == "OPTIONS" {
fmt.Println(context.Request.Header)
context.AbortWithStatus(200)
} else {
context.Next()
}
}
}
字段说明 :
Access-Control-Allow-Origin
首先,客户端请求时要带上一个Origin,用来说明,本次请求来自哪个源(协议 + 域名 + 端口)。服务器根据这个值,决定是否同意这次请求。然后服务端在返回时需要带上这个字段,并把对方传过来的值返回去。告知客户端,允许这次请求。这个字段也可以设置为*,即允许所有客户端访问。但是这样做会和Access-Control-Allow-Credentials 起冲突。可能导致跨域请求失败。
Access-Control-Allow-Credentials
这个字段是一个BOOL值,可以允许客户端携带一些校验信息,比如cookie等。如果设置为Access-Control-Allow-Origin:*,而该字段是true,并且客户端开启了withCredentials, 仍然不能正确访问。需要把Access-Control-Allow-Origin的值设置为客户端传过来的值。
五、其他
跨域分为 简单请求 和 复杂请求:
简单请求是不会发 options 预检验请求, 这是在调试界面只看到一次 req 的原因。
有些浏览器标签是自带跨域的, 如 imge。
(部分源自其他文章, 侵删)