介绍一下跨域相关的内容。

同源策略(same-origin policy)

  1. 浏览器有一种同源策略,是一种安全机制。
  2. 同源:域名、协议、端口三者都相同则为同源,否则认为是跨域。
(1)同一个域名下的不同uri,同源。
(2)http和https,不同源。
(3)端口号不同,不同源。
(4)域名和其ip,不同源。
(5)不同二级子域(如www和其它),不同源。
(6)不同域名,不同源。
  1. 简单来讲,同源策略就是浏览器为了保证用户信息的安全,防止恶意的网站窃取数据,禁止不同域之间的JS进行交互。

解决跨域问题的方式

跨域资源共享(CORS)

  1. CROS,全称是跨域资源共享 (Cross-origin resource sharing),它的提出就是为了解决跨域请求的。
  2. 可以从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 认证相关数据)。

  1. Content-Type不属于以下MIME类型的,都属于预检请求:
application/x-www-form-urlencodedmultipart/form-datatext/plain
  1. application/json的请求会在正式通信之前,增加一次"预检"请求,这次"预检"请求会带上头部信息 Access-Control-Request-Headers中的字段。
  2. 服务器回应时,返回的头部信息如果不包含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()) //允许跨域