CORS
CORS,全称Cross-Origin Resource Sharing,是一种允许当前域(domain)的资源(比如html/js/web service)被其他域(domain)的脚本请求访问的机制,通常由于同域安全策略(the same-origin security policy)浏览器会禁止这种跨域请求。
CORS是一种允许当前域(domain)的资源(比如html/js/web service)被其他域(domain)的脚本请求访问的机制,通常由于同域安全策略(the same-origin security policy)浏览器会禁止这种跨域请求。
CORS也有一些限制,两种模型可以实现:
1.简单模型
支持get/post/put/delete请求,例如返回Access-Control-Allow-Origin:*,但是不允许自定义header且会忽略cookies,且post数据格式有限制,只支持‘text/plain’,‘application/x-www-urlencoded’and’multipart/form-data’,其中’text/plain’默认支持,后面两种需要下面的预检请求和服务器协商。
2.协商模型/预检请求(Preflighted Request)
举例:浏览器发出PUT请求,OPTION请求返回Access-Control-Allow-Origin:,Access-Control-Allow-Methods:’PUT’,服务器同意所有域的PUT请求,浏览器收到并继续发出真正的PUT请求,服务器响应并再次返回Access-Control-Allow-Origin:,允许浏览器的脚本执行服务器返回的数据。
跨域请求:发起请求的域和该请求指向的资源所在域不同,只要协议、域名、端口有一个不同就是跨域请求浏览器地址栏中的协议域名端口,与网页中使用js请求的协议域名端口有一者不同就是跨域。
测试
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>demo</title>
</head>
<body>
<h1 id="json"></h1>
<script>
function doit() {
let xhr = new XMLHttpRequest();
xhr.open('GET', 'http://localhost/json');
xhr.send();
}
</script>
<input type="button" value="点我测试跨域问题" onclick="doit()">
</body>
</html>
func JsonGet() gin.HandlerFunc {
return func(ctx *gin.Context) {
ctx.JSON(http.StatusOK, gin.H{
"message": "返回json数据",
})
}
}
运行JsonGet然后用浏览器打开html文件。点击"点我测试跨域问题"按钮,页面数据产生。打开浏览器控制台。可见出现了跨域问题。
两种Gin框架解决办法
使用jsonp
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>demo</title>
</head>
<body>
<h1 id="json"></h1>
<h1 id="jsonp"></h1>
<script>
function doit() {
let xhr = new XMLHttpRequest();
xhr.open('GET', 'http://localhost/json');
xhr.send();
}
function write(obj) {
document.getElementById("jsonp").innerText = 'cors:'+JSON.stringify(obj);
}
</script>
<input type="button" value="点我测试跨域问题" onclick="doit()">
<script src="http://localhost/jsonp?callback=write"></script>
</body>
</html>
运行jsonpGet,然后用浏览器打开html文件。<script src="http://localhost/jsonp?callback=write"></script>
回调了函数write对h1标签进行了赋值操作。
使用中间件
package middleware
import (
"github.com/gin-gonic/gin"
"net/http"
)
func Cors() gin.HandlerFunc {
return func(ctx *gin.Context) {
method := ctx.Request.Method
ctx.Header("Access-Control-Allow-Origin", "*")
ctx.Header("Access-Control-Allow-Headers", "Content-Type,AccessToken,X-CSRF-Token, Authorization, Token, x-token")
ctx.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE, PATCH, PUT")
ctx.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers, Content-Type")
ctx.Header("Access-Control-Allow-Credentials", "true")
if method == "OPTIONS" {
ctx.AbortWithStatus(http.StatusNoContent)
}
}
}
Reference
https://baike.baidu.com/item/CORS/16411212?fr=aladdin