使用go語言實現(xiàn)cors中間件
一、概述
CORS(Cross-Origin Resource Sharing)是一種瀏覽器安全機制,用于控制在Web應(yīng)用程序中不同源(Origin)之間的資源共享。一個源是由協(xié)議(例如http或https)、主機(例如 www.example.com)、以及端口(例如80或443)組成的組合。CORS允許服務(wù)器定義哪些源可以訪問其資源,以及哪些HTTP方法和頭部可以在跨源請求中使用。
要點:
- 同源策略(Same-Origin Policy):Web瀏覽器實施了同源策略,它限制了一個頁面中加載的資源只能來自相同的源,以防止而已站點獲取用戶的敏感信息。這意味著默認(rèn)情況下,跨域請求是被瀏覽器禁止的。
- 跨源HTTP請求:當(dāng)一個Web頁面需要從不同源的服務(wù)器獲取數(shù)據(jù)時,例如通過AJAX請求或嵌入其他站點的資源(如字體、圖片或腳本),就會設(shè)計到跨源HTTP請求。
- CORS解決跨域問題: CORS是一種機制,允許服務(wù)器在響應(yīng)中添加HTTP標(biāo)頭來指示瀏覽器允許跨域請求。這些標(biāo)頭包括”Access-Control-Allow-Origin“、”Access-Control-Allow-Methods“、”Access-Control-Allow-Headers“等
- 簡單請求和預(yù)檢請求:瀏覽器將跨域HTTP請求分為兩種類型:簡單請求(Simple Request)和預(yù)檢請求(Preflight Request)。簡單請求就是常見的GET、POST請求,而預(yù)檢請求時一種用于檢查服務(wù)器是否支持某些請求的OPTION請求。
- 服務(wù)器配置:CORS的服務(wù)器配置通常在服務(wù)器端完成。服務(wù)器需要響應(yīng)OPTIONS請求并在響應(yīng)頭中包含CORS標(biāo)頭來指定允許的來源、HTTP方法和頭部。服務(wù)器還可以選擇性地要求攜帶憑據(jù)(credentials)
- 瀏覽器行為:瀏覽器在發(fā)送跨域請求時會自動附加Origin頭,然后根據(jù)服務(wù)器的響應(yīng)判斷是否允許訪問資源。如果CORS設(shè)置不正確,瀏覽器會阻止頁面訪問響應(yīng)的數(shù)據(jù)。
二、簡單請求和預(yù)檢請求
簡單請求
1、判定條件
需要同時滿足以下條件,瀏覽器會認(rèn)為它是一個簡單請求
- 請求方法屬于其中一種:GET、POST、HEAD
- 請求包僅包含安全的字段,常見字段:Accept、Accept-Language、Content-Language、Content-Type、DPR、Downlink、Save-Data、Viewport-Width、Width
- 請求頭如果包含Content-Type,僅限如下值:text/plain、multipart/form-data、application/x-www-form-urlencoded
2、簡單請求交互
①當(dāng)瀏覽器判某個跨域請求時簡單請求時,會在請求頭中自動添加Origin字段
GET /cors HTTP/1.1 Host: example.com Connection: keep-alive ... Referer: http://local.com/index.html Origin: http://local.com //Origin字段會告訴服務(wù)器,是哪個源地址在跨域請求
②服務(wù)器響應(yīng)頭中應(yīng)包含Access-Control-Allow-Origin ,當(dāng)服務(wù)器收到請求后,如果允許改請求跨域訪問,需要在響應(yīng)頭中添加Access-Control-Allow-Origin字段
HTTP/1.1 200 OK Date: Tue, 21 Jun 2023 08:03:35 GMT ... Access-Control-Allow-Origin: http://local.com ... 消息體中的數(shù)據(jù)
當(dāng)瀏覽器看到服務(wù)器允許自己訪問后,于是,它就把響應(yīng)順利的交給js
預(yù)檢請求
1、對于預(yù)檢請求,請求步驟如下:
- 瀏覽器發(fā)送預(yù)檢請求,詢問服務(wù)器是否允許
- 服務(wù)器響應(yīng)是否允許
- 瀏覽器發(fā)送真實請求
- 服務(wù)器完成真實的響應(yīng)
2、步驟請求演示
要發(fā)送的請求包:
POST /cors HTTP/1.1
Host: example.com
Connection: keep-alive ...
Referer: http://local.com/index.html
Origin: http://local.com
{"name": "admin", "age": 20}
①瀏覽器發(fā)送預(yù)檢請求
OPTIONS /cors HTTP/1.1 Host: example.com ... Origin: http://local.com Access-Control-Request-Method: POST Access-Control-Request-Headers: a, b, content-type
ps:這并非想要發(fā)出的真實請求,請求中不包含響應(yīng)頭和也沒有消息體。
預(yù)檢請求特征:
請求方法為OPTIONS 沒有請求體
- 請求頭中包含 Origin:請求的源,和簡單請求的含義一致
- Access-Control-Request-Method:后續(xù)的真實請求將使用的請求方法
- Access-Control-Request-Headers:后續(xù)的真實請求會改動的請求頭
②服務(wù)器允許
服務(wù)器收到預(yù)檢請求后,可以檢查預(yù)檢請求中包含的信息,如果允許這樣的請求,需要響應(yīng)下面的消息格式
HTTP/1.1 200 OK ... Access-Control-Allow-Origin: http://local.com Access-Control-Allow-Methods: POST Access-Control-Allow-Headers: a, b, content-type Access-Control-Max-Age: 86400 ...
對于預(yù)檢請求,不需要響應(yīng)任何的消息體,只需要在響應(yīng)頭中添加:
Access-Control-Allow-Origin:和簡單請求一樣,表示允許的源 Access-Control-Allow-Methods:表示允許的后續(xù)真實的請求方法 Access-Control-Allow-Headers:表示允許改動的請求頭 Access-Control-Max-Age:告訴瀏覽器,多少秒內(nèi),對于同樣的請求源、方法、頭,都不需要再發(fā)送預(yù)檢請求了
③瀏覽器發(fā)送真實請求
預(yù)檢被服務(wù)器允許后,瀏覽器就會發(fā)送真實請求了,上面的代碼會發(fā)送下面的請求數(shù)據(jù)
POST /cors HTTP/1.1 Host: example.com Connection: keep-alive ... Referer: http://local.com/index.html Origin: http://local.com {"name": "admin", "age": 20}
④服務(wù)器響應(yīng)真實請求
HTTP/1.1 200 OK Date: Tue, 21 Jun 2023 08:03:35 GMT ... Access-Control-Allow-Origin: http://local.com ... 添加用戶成功
三、使用go的gin框架實現(xiàn)cors配置
使用go的gin框架的話,說白了就是添加一個中間件,Gin官方提供CORS中間件,可以很方便的使用 cors解決跨域問題。
1、安裝
使用命令安裝該中間件
go get github.com/gin-contrib/cors
2、函數(shù)
cors中間件提供三個函數(shù),代表三種使用方式,分別是NEW、DefaultConfig、Default。
- NEW方式
可以接收 CORS 中間件的配置項,可通過自定義配置項,滿足任意需要跨域的場景。
示例: router.Use(cors.New(cors.Config{ AllowOrigins: []string{"https://foo.com"}, AllowMethods: []string{"PUT", "PATCH"}, AllowHeaders: []string{"Origin"}, ExposeHeaders: []string{"Content-Length"}, AllowCredentials: true, AllowOriginFunc: func(origin string) bool { return origin == "https://github.com" }, MaxAge: 12 * time.Hour, })) //New 函數(shù)接收配置項,返回一個用戶自定義的 CORS 中間件,綁定到路由中。
三、使用go的gin框架實現(xiàn)cors配置
使用go的gin框架的話,說白了就是添加一個中間件,Gin官方提供CORS中間件,可以很方便的使用 cors解決跨域問題。
1、安裝
使用命令安裝該中間件
go get github.com/gin-contrib/cors
2、函數(shù)
cors中間件提供三個函數(shù),代表三種使用方式,分別是NEW、DefaultConfig、Default。
- NEW方式
可以接收 CORS 中間件的配置項,可通過自定義配置項,滿足任意需要跨域的場景。
示例: router.Use(cors.New(cors.Config{ AllowOrigins: []string{"https://foo.com"}, AllowMethods: []string{"PUT", "PATCH"}, AllowHeaders: []string{"Origin"}, ExposeHeaders: []string{"Content-Length"}, AllowCredentials: true, AllowOriginFunc: func(origin string) bool { return origin == "https://github.com" }, MaxAge: 12 * time.Hour, })) //New 函數(shù)接收配置項,返回一個用戶自定義的 CORS 中間件,綁定到路由中。
配置項說明:
- AllowAllOrigins bool 允許所有請求源。
- AllowOrigins []string 指定允許請求源的列表,如果列表中存在
*
,則允許所有請求源,默認(rèn)值是[]
。 - AllowOriginFunc func(origin string) bool 接收參數(shù) origin,函數(shù)體中的驗證邏輯返回是否允許跨域請求。該配置項優(yōu)先級高于 AllowOrigins []string,如果設(shè)置該配置項,
AllowOrigins []string
配置項的設(shè)置被忽略。 AllowMethods []string
允許的請求方式,默認(rèn)值是GET
,POST
,PUT
,PATCH
,DELETE
,HEAD
,和OPTIONS
。AllowHeaders []string
用在對預(yù)請求的響應(yīng)中,指示實際的請求中可以使用哪些 HTTP 請求頭。AllowCredentials bool
表示請求附帶請求憑據(jù)時是否響應(yīng)請求,例如cookie
、HTTP authentication
或客戶端 SSL 證書。ExposeHeaders []string
可以在響應(yīng)中顯示的請求頭。MaxAge time.Duration
指示預(yù)請求的結(jié)果能被緩存多久。AllowWildcard bool
添加請求源是否允許使用通配符,例如http://some-domain/*
,https://api.
或http://some.*.subdomain.com
。AllowBrowserExtensions bool
允許使用常用的瀏覽器的擴展模式。AllowWebSockets bool
允許使用 WebSocket 協(xié)議。AllowFiles bool
允許使用file://
協(xié)議。
- DefaultConfig方式
默認(rèn)設(shè)置一些通用配置項,我們可以直接使用,也可以在此基礎(chǔ)上添加我們需要的其他配置項。
func Default() gin.HandlerFunc { config := DefaultConfig() config.AllowAllOrigins = true return New(config) }
3、某段配置代碼分析
//設(shè)置cors中間件 func Cors() gin.HandlerFunc { return func(c *gin.Context) { method := c.Request.Method //獲取請求包的http請求方法 origin := c.Request.Header.Get("Origin") //獲取請求包的head頭的Origin參數(shù)值 var headerkeys []string for k := range c.Request.Header { headerkeys = append(headerkeys, k) } headerStr := strings.Join(headerkeys, ", ") //將請求包中head頭部分的參數(shù)用","連接成字符串 //檢查請求頭不為空 if headerStr != "" { //如果請求頭不為空,將請求頭的鍵名添加到一個字符串中,以便在設(shè)置響應(yīng)頭時包含這些鍵名。 headerStr = fmt.Sprintf("access-control-allow-origin, access-control-allow-headers,%s", headerStr) } else { headerStr = "access-control-allow-origin, access-control-allow-headers" } //檢查請求頭中origin是否為空 if origin != "" { //設(shè)置響應(yīng)頭中的"Access-Control-Allow-Origin"字段,允許任何域名訪問資源(這是一個簡單的CORS策略,實際應(yīng)用中可能需要更嚴(yán)格的控制)。 c.Writer.Header().Set("Access-Control-Allow-Origin", "*") c.Header("Access-Control-Allow-Methods", "POST,GET,OPTIONS,PUT,DELETE, UPDATE") c.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") c.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") // 跨域關(guān)鍵設(shè)置 讓瀏覽器可以解析 c.Header("Access-Control-Max-Age", "172800") // 緩存請求信息 單位為秒 c.Header("Access-Control-Allow-Credentials", "false") // 跨域請求是否需要帶cookie信息 默認(rèn)設(shè)置為true c.Set("content-type", "application/json") // 設(shè)置返回格式是json } //放行所有OPTIONS方法 if method == "OPTIONS" { c.JSON(http.StatusOK, "Options Request!") } } }
以上就是使用go語言實現(xiàn)cors中間件的詳細(xì)內(nèi)容,更多關(guān)于go實現(xiàn)cors中間件的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Golang Gorm實現(xiàn)自定義多態(tài)模型關(guān)聯(lián)查詢
GORM 是一個流行的開源 ORM (Object-Relational Mapping) 庫,專為 Go 語言設(shè)計,它簡化了與 SQL 數(shù)據(jù)庫的交互,GORM 封裝了數(shù)據(jù)庫操作,使得開發(fā)者能夠通過簡單的鏈?zhǔn)秸{(diào)用來執(zhí)行 CRUD,本文給大家介紹了Golang Gorm實現(xiàn)自定義多態(tài)模型關(guān)聯(lián)查詢,需要的朋友可以參考下2024-11-11