介绍一下跨域相关的内容。
同源策略(same-origin policy)
- 浏览器有一种同源策略,是一种安全机制。
- 同源:域名、协议、端口三者都相同则为同源,否则认为是跨域。
(1)同一个域名下的不同uri,同源。
(2)http和https,不同源。
(3)端口号不同,不同源。
(4)域名和其ip,不同源。
(5)不同二级子域(如www和其它),不同源。
(6)不同域名,不同源。
- 简单来讲,同源策略就是浏览器为了保证用户信息的安全,防止恶意的网站窃取数据,禁止不同域之间的JS进行交互。
解决跨域问题的方式
跨域资源共享(CORS)
- CROS,全称是跨域资源共享 (Cross-origin resource sharing),它的提出就是为了解决跨域请求的。
- 可以从nginx层进行支持跨域配置
location / {
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
add_header Access-Control-Allow-Headers 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization';
if ($request_method = 'OPTIONS') {
return 204;
}
}
预检请求(preflight request)
跨域资源共享(CORS)标准新增了一组 HTTP 首部字段,允许服务器声明哪些源站有权限访问哪些资源。另外,规范要求,对那些可能对服务器数据产生副作用的HTTP 请求方法(特别是 GET 以外的 HTTP 请求,或者搭配某些 MIME 类型的 POST 请求),浏览器必须首先使用 OPTIONS 方法发起一个预检请求(preflight request),从而获知服务端是否允许该跨域请求。服务器确认允许之后,才发起实际的 HTTP 请求。在预检请求的返回中,服务器端也可以通知客户端,是否需要携带身份凭证(包括 Cookies 和 HTTP 认证相关数据)。
- Content-Type不属于以下MIME类型的,都属于预检请求:
application/x-www-form-urlencodedmultipart/form-datatext/plain
- application/json的请求会在正式通信之前,增加一次"预检"请求,这次"预检"请求会带上头部信息 Access-Control-Request-Headers中的字段。
- 服务器回应时,返回的头部信息如果不包含Access-Control-Allow-Headers字段则表示不接受非默认的字段信息。
Go语言的Gin框架跨域中间件
package middlewares
import (
"github.com/gin-gonic/gin"
)
// 处理跨域请求,支持options访问
func Cors() gin.HandlerFunc {
return func(c *gin.Context) {
method := c.Request.Method
c.Header("Content-Type", "text/html;charset=utf-8")
c.Header("Access-Control-Allow-Origin", "*")
c.Header("Access-Control-Allow-Methods", "POST,GET,OPTIONS,DELETE")
c.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers, Content-Type")
c.Header("Access-Control-Allow-Credentials", "true")
c.Header("Access-Control-Allow-Headers", "Content-Type,Content-Length,Accept-Encoding,X-Requested-with, Origin") // 设置允许自定义请求头的字段
//放行所有OPTIONS方法
if method == "OPTIONS" {
c.JSON(200, gin.H{})
c.Abort()
}
// 处理请求
c.Next()
}
}
然后在main函数中,注册中间件:
// 加载自定义中间件
r.Use(middlewares.Cors()) //允许跨域