跨域问题

一、 介绍

为什么出现跨域问题?

源自浏览器的核心安全功能: 同源策略 , 即浏览器执行的 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。

(部分源自其他文章, 侵删)

你可能感兴趣的:(跨域问题)