<head>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js"></script>
</head>
<body>
<script>
$(document).ready(function(){
const url = "http://127.0.0.1:8080/api/v1/test";
$.ajax({
url: url,
type: "GET",
success:function(result){
console.log(result)
},
error:function(error){
console.log(error)
}
})
})
</script>
</body>
</html>

這時如果在瀏覽器中打開這個文件,或者使用nginx作為靜態代理,只要該文件「不是」通過http://127.0.0.1:8080 這個域發起的請求,則由于瀏覽器的同源策略都會被攔截。

Access to XMLHttpRequest at 'http://127.0.0.1:8080/api/v1/test' from origin 'http://127.0.0.1:8888' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

gin后端解決跨域

瀏覽器在發送http請求的時候,會在header中記錄Origin信息

我們先來看下gin是如何獲取請求 header 信息的,gin 通過 *gin.Context.Request.Header 來獲取到請求頭信息

func (ApiV1) Get(c *gin.Context)  {
fmt.Println(c.Request.Header)
c.JSON(200, gin.H{"msg": "handlers get request!"})
}

想要獲取到Origin 信息,Header 本身是個 map[string][]string 類型數據,可能通過Get方法來獲取Origin信息

在響應頭中將該域添加到 Access-Control-Allow-Origin中,并同時設置 Access-Control-Allow-Methods

func (ApiV1) Get(c *gin.Context)  {
origin := c.Request.Header.Get("Origin") //請求頭部
if origin!=""{
// 將該域添加到allow-origin中
c.Header("Access-Control-Allow-Origin", origin) //
c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE, UPDATE")
c.Header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Authorization")
c.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers, Cache-Control, Content-Language, Content-Type")
//允許客戶端傳遞校驗信息比如 cookie
c.Header("Access-Control-Allow-Credentials", "true")
}
c.JSON(200, gin.H{"msg": "handlers get request!"})
}

這時再訪問剛才的html文件就可以正常的請求到了數據。

寫成中間件

上面只是針對某一個接口,如果想要所有的接口都可以被跨域請求,則可以將其寫成一個中間件,上面是將所有的域都允許跨域請求,其實還是有點問題的,這里我將允許跨域請求的地址寫到一個map中,本來想寫到數組或者slice中,但是發現在判斷是否存在的時候,golang中并沒有in 運算符,需要遍歷數組或者slice,復雜度為O(n) ,還是使用map吧。

另外如果請求方法是OPTIONS 的話,如websocket請求會先發一個OPTIONS請求,這時可以不進行校驗,直接返回

package midwares

import (
"github.com/gin-gonic/gin"
)

func CheckCors() gin.HandlerFunc {
//這里可以處理一些別的邏輯
return func(c *gin.Context) {
// 定義一個origin的map,只有在字典中的key才允許跨域請求
var allowOrigins = map[string]struct{}{
"http://127.0.0.1:8888": struct {}{},
"https://www.yangyanxing.com": struct {}{},
}
origin := c.Request.Header.Get("Origin") //請求頭部
method := c.Request.Method
if method == "OPTIONS"{
c.AbortWithStatus(http.StatusNoContent)
}
if origin!=""{
if _, ok:=allowOrigins[origin];ok{
c.Header("Access-Control-Allow-Origin", origin)
c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE, UPDATE")
c.Header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Authorization")
c.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers, Cache-Control, Content-Language, Content-Type")
c.Header("Access-Control-Allow-Credentials", "true")
}
}
c.Next()
}
}

在main.go中加入該中間件

func main() {
r := gin.Default()
r.Use(midwares.CheckCors())
....
r.Run(":8080")

之后就可以完成跨域請求了。

文章轉自微信公眾號@序語程言

上一篇:

Go 語言 API 文檔利器:Swagger保姆級使用指南大揭秘!

下一篇:

.NET 7.0+WebAPI 后端架構實戰
#你可能也喜歡這些API文章!

我們有何不同?

API服務商零注冊

多API并行試用

數據驅動選型,提升決策效率

查看全部API→
??

熱門場景實測,選對API

#AI文本生成大模型API

對比大模型API的內容創意新穎性、情感共鳴力、商業轉化潛力

25個渠道
一鍵對比試用API 限時免費

#AI深度推理大模型API

對比大模型API的邏輯推理準確性、分析深度、可視化建議合理性

10個渠道
一鍵對比試用API 限時免費