这是我参与「第三届青训营 -后端场」笔记创作活动的第二篇笔记
同源策略
为了防止XSS攻击等安全问题,浏览器客户端应当仅请求于来自同一个域的资源 因此会阻止一个域加载的脚本去获取另一个域的资源,也就是说页面和ajax请求只能访问(和发起请求者)同域下的其他资源。
- 只要协议、域名IP、端口中任意一个不同,就是不同的域,否则将视为跨域访问。
- 发生跨域时,在浏览器中响应码为404,并且出现 Access-Control-Allow-Oringin
- HTML 标签中,有些标签是允许跨域的,例如:
预检请求
- 预检请求即请求方法为 OPTIONS 的请求
- 非简单请求(且跨域的情况) 发送前需要额外发送一次预检请求,用作嗅探作用
- 目的是查看服务端是否支持即将要发送的请求,判断是否安全
- 当预检请求被成功响应,服务器返回当前请求能否被正常接收和处理,能接受才会发送实际HTTP请求
- 预检请求的结果可以通过设置 Access-Control-Max-Age 进行缓存
- 目的是查看服务端是否支持即将要发送的请求,判断是否安全
- 当预检请求被成功响应,服务器返回当前请求能否被正常接收和处理,能接受才会发送实际HTTP请求
- 预检请求的结果可以通过设置 Access-Control-Max-Age 进行缓存
- 非简单由于有预检请求,一条变两条,服务器压力增大,解决方法是:
- 预检请求授权逻辑不轻易改变, 可以进行缓存
- 在设定缓存时间内同样的非简单请求无需预检,直接发送原请求
- 预检请求授权逻辑不轻易改变, 可以进行缓存
- 在设定缓存时间内同样的非简单请求无需预检,直接发送原请求
跨域解决方案
前端方案
- JSONP
- PROXY 反向代理 后端方案
- CORS - 跨域资源共享
- 使用额外的HTTP头附加额外信息通知浏览器可以访问其他域
- URL响应头包含 Accss-Control-xxx 指明请求允许跨域(远程服务器相应资源经过授权) 主要介绍 CORS 解决跨域的方式,在 gin 中注册如下的中间件,用于给预检请求进行响应
func Cors() gin.HandlerFunc {
return func(c *gin.Context) {
//获取请求方法
method := c.Request.Method
c.Header("Access-Control-Allow-Origin", "*")
//允许的请求头
c.Header("Access-Control-Allow-Headers", "Content-Type,AccessToken,X-CSRF-Token, Authorization, Token, x-token,headerUserId,headerUserToken")
//允许的请求方法
c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE, PATCH, PUT")
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")
if method == "OPTIONS" {
//数据体无内容,返回 204 状态
c.AbortWithStatus(http.StatusNoContent)
}
}
}