浏览器发送options预检请求的前提:
在非简单请求且跨域的情况下,浏览器会发起options预检请求
简单请求
需要满足以下两个条件
1. 请求方法
get
head
post
2. http的头信息不超过以下几种字段
Accept
Accept-Language
Content-Language
Last-Event-ID
Content-Type:(只限于application/x-www-form-urlencoded、multipart/form-data、text/plain)
复杂请求
非简单请求即复杂请求,常见的复杂请求有
1. 请求方法为put或delete
2. Content-Type字段类型为:application/json
3. 添加额外的http header 比如:access_token
在跨域的情况下,非简单请求会先发起一次空body的OPTIONS预检请求
用于向服务器请求权限信息,等预检请求被成功响应后,才发起真正的http请求
浏览器的预检请求可以通过设置:Access-Control-Max-Age进行缓存
跨域访问的问题
OPTIONS请求
全局跨域访问中间件
// 跨域访问:cross origin resource share
func Cors() gin.HandlerFunc {
return func(context *gin.Context) {
method := context.Request.Method
origin := context.Request.Header.Get("Origin")
var headerKeys []string
for k, _ := range context.Request.Header {
headerKeys = append(headerKeys, k)
}
headerStr := strings.Join(headerKeys, ",")
if headerStr != "" {
headerStr = fmt.Sprintf("access-control-allow-origin, access-control-allow-headers, %s", headerStr)
} else {
headerStr = fmt.Sprintf("access-control-allow-origin, access-control-allow-headers")
}
if origin != "" {
context.Writer.Header().Set("Access-Control-Allow-Origin", "*")
context.Header("Access-Control-Allow-Origin", "http://127.0.0.1:8080") // 设置允许访问所有域: *
context.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE,UPDATE")
context.Header("Access-Control-Allow-Headers", "Authorization, Content-Length, X-CSRF-Token, Token,session,X_Requested_With,Accept, Origin, Host, Connection, Accept-Encoding, Accept-Language,DNT, X-CustomHeader, Keep-Alive, User-Agent, X-Requested-With, If-Modified-Since, Cache-Control, Content-Type, Pragma")
context.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers,Cache-Control,Content-Language,Content-Type,Expires,Last-Modified,Pragma,FooBar")
context.Header("Access-Control-Max-Age", "172800")
context.Header("Access-Control-Allow-Credentials", "false")
context.Set("content-type", "application/json") //// 设置返回格式是json
}
if method == "OPTIONS" {
context.JSON(http.StatusOK, "Options Request!")
}
// 处理请求
context.Next()
}
}
跨域解决办法2
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")
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" {
c.AbortWithStatus(http.StatusNoContent)
}
}
}
跨域前端测试代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>
</head>
<body>
<button type="button" id="query">请求数据</button>
<div id="content" style="background-color: aqua; width: 300px; height: 500px;"></div>
</body>
<script type="text/javascript">
$("#query").click(function () {
$.ajax(
{
url: "http://127.0.0.1:8021/u/v1/user/list",
dataType: "json",
type: "get",
beforeSend: function (request) {
request.setRequestHeader("x-token", "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJJRCI6MjQsIk5pY2tOYW1lIjoi6ams6aao5b2kIiwiQXV0aG9yaXR5SWQiOjIsImV4cCI6MTY0ODUzODE5OSwiaXNzIjoic2Fua3VhbiIsIm5iZiI6MTY0NTk0NjE5OX0.0mkxmRhPgjDHSr48fbNn9I9FtPUGlop3807kAbJb74c")
},
success: function (result) {
console.log(result.data)
$("#content").text(result.data)
},
error: function (data) {
alert("请求出错")
}
}
)
})
</script>
</html>