Go中跨域Cors中間件的實(shí)現(xiàn)
通過(guò)建造者模式創(chuàng)建我們的跨域中間件Cors
我們了解到,當(dāng)使用XMLHttpRequest發(fā)送請(qǐng)求時(shí),如果瀏覽器發(fā)現(xiàn)違反了同源策略就會(huì)自動(dòng)加上一個(gè)請(qǐng)求頭 origin;
后端在接受到請(qǐng)求后確定響應(yīng)后會(huì)在 Response Headers 中加入一個(gè)屬性 Access-Control-Allow-Origin;
瀏覽器判斷響應(yīng)中的 Access-Control-Allow-Origin 值是否和當(dāng)前的地址相同,匹配成功后才繼續(xù)響應(yīng)處理,否則報(bào)錯(cuò)
缺點(diǎn):忽略 cookie,瀏覽器版本有一定要求
同時(shí),結(jié)合項(xiàng)目實(shí)際,我們可以使用一個(gè)config結(jié)構(gòu)體來(lái)存放我們的配置,這里可以使用建造者模式進(jìn)行靈活的管理
所以cors中,我們也添加與config相同的字段
Config:
// CorsConfig 使用了建造者模式 type CorsConfig struct { AllowOrigins []string AllowMethods []string AllowHeaders []string //如果想要讓客戶端可以訪問(wèn)到其他的標(biāo)頭,服務(wù)器必須將它們?cè)?Access-Control-Expose-Headers 里面列出來(lái).eg:"Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers,Cache-Control,Content-Language,Content-Type,Expires ExposeHeaders []string //這個(gè)響應(yīng)頭表示 preflight request (預(yù)檢請(qǐng)求)的返回結(jié)果(即 Access-Control-Allow-Methods 和Access-Control-Allow-Headers 提供的信息)可以被緩存多久。 AccessControlMaxAge string //告知瀏覽器是否可以將對(duì)請(qǐng)求的響應(yīng)暴露給前端 JavaScript 代碼。 AccessControlAllowCredentials bool }
Cors:
type Cors struct { AllowOrigins []string AllowMethods []string AllowHeaders []string //如果想要讓客戶端可以訪問(wèn)到其他的標(biāo)頭,服務(wù)器必須將它們?cè)?Access-Control-Expose-Headers 里面列出來(lái).eg:"Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers,Cache-Control,Content-Language,Content-Type,Expires ExposeHeaders []string //這個(gè)響應(yīng)頭表示 preflight request (預(yù)檢請(qǐng)求)的返回結(jié)果(即 Access-Control-Allow-Methods 和Access-Control-Allow-Headers 提供的信息)可以被緩存多久。 AccessControlMaxAge string //告知瀏覽器是否可以將對(duì)請(qǐng)求的響應(yīng)暴露給前端 JavaScript 代碼。 AccessControlAllowCredentials bool }
當(dāng)然,我們的Config需要一些方法來(lái)控制字段的值
func (c *CorsConfig) AddOrigins(origins ...string) *CorsConfig { c.AllowOrigins = append(c.AllowOrigins, origins...) return c } func (c *CorsConfig) AddMethods(methods ...string) *CorsConfig { c.AllowMethods = append(c.AllowMethods, methods...) return c } func (c *CorsConfig) AddHeaders(headers ...string) *CorsConfig { c.AllowHeaders = append(c.AllowHeaders, headers...) return c } func (c *CorsConfig) AddExposeHeaders(exposeHeaders ...string) *CorsConfig { c.ExposeHeaders = append(c.ExposeHeaders, exposeHeaders...) return c } func (c *CorsConfig) SetAccessControlMaxAge(ms string) *CorsConfig { c.AccessControlMaxAge = ms return c } func (c *CorsConfig) SetAccessControlAllowCredentials(isAllow bool) *CorsConfig { c.AccessControlAllowCredentials = isAllow return c }
同時(shí),為了方便,我們可以給出一個(gè)方法來(lái)設(shè)置默認(rèn)的情況
func DefaultCorsConfig() *CorsConfig { return &CorsConfig{ AllowOrigins: []string{"*"}, AllowMethods: []string{"POST", "POST", "GET", "OPTIONS", "PUT", "DELETE", "UPDATE"}, AllowHeaders: []string{"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"}, ExposeHeaders: []string{"Content-Length", "Access-Control-Allow-Origin", "Access-Control-Allow-Headers", "Cache-Control", "Content-Languge", "Caontent-Type", "Expires", "Last-Modified", "Pragma", "FooBar"}, AccessControlMaxAge: "200000", AccessControlAllowCredentials: true, } }
最后,實(shí)現(xiàn)將config應(yīng)用到Cors中的方法和應(yīng)用Cors的設(shè)置的方法
將config應(yīng)用到Cors中的方法:
func (cors *Cors) SetCorsConfig(c *CorsConfig) { cors.AccessControlMaxAge = c.AccessControlMaxAge cors.ExposeHeaders = c.ExposeHeaders cors.AllowOrigins = c.AllowOrigins cors.AllowHeaders = c.AllowHeaders cors.AllowMethods = c.AllowMethods cors.AccessControlAllowCredentials = c.AccessControlAllowCredentials }
應(yīng)用Cors的設(shè)置的方法 :
func (cors *Cors) Apply() sgin8.HandlerFunc { return func(context *sgin8.Context) { method := context.Req.Method origin := context.Req.Header.Get("Origin") if origin != "" { context.SetHeader("Access-Control-Allow-Origin", strings.Join(cors.AllowOrigins, ",")) // 設(shè)置允許訪問(wèn)所有域 context.SetHeader("Access-Control-Allow-Methods", strings.Join(cors.AllowMethods, ",")) context.SetHeader("Access-Control-Allow-Headers", strings.Join(cors.AllowHeaders, ",")) context.SetHeader("Access-Control-Expose-Headers", strings.Join(cors.ExposeHeaders, ",")) context.SetHeader("Access-Control-Max-Age", cors.AccessControlMaxAge) context.SetHeader("Access-Control-Allow-Credentials", strconv.FormatBool(cors.AccessControlAllowCredentials)) } else { log.Printf("This request haven not set the 'Origin' in Header") } if method == "OPTIONS" { context.JSON(http.StatusOK, "Options Request!") } //處理請(qǐng)求 context.Next() } }
當(dāng)然,我們提供快速開(kāi)始的方案:
func (c *CorsConfig) Build() sgin8.HandlerFunc { cors := &Cors{} cors.SetCorsConfig(c) return cors.Apply() }
demo:
func main() { //eg1: r := sgin8.Default() config1 := sgin8.DefaultCorsConfig() cors1 := sgin8.Cors{} cors1.SetCorsConfig(config1) r.Use(cors1.Apply()) //eg2 r.Use(sgin8.DefaultCorsConfig().Build()) //eg3 config3 := sgin8.CorsConfig{} config3.SetAccessControlMaxAge("200000").SetAccessControlAllowCredentials(true).AddMethods("GET", "POST") r.Use(config3.Build()) //eg4 config4 := &sgin8.CorsConfig{} config4.SetAccessControlMaxAge("200000").SetAccessControlAllowCredentials(true).AddMethods("GET", "POST") cors4 := sgin8.Cors{} cors4.SetCorsConfig(config4) cors4.Apply() r.GET("/", func(c *sgin8.Context) { c.String(http.StatusOK, "Hello wxk\n") }) // index out of range for testing Recovery() r.GET("/panic", func(c *sgin8.Context) { names := []string{"wxk"} c.String(http.StatusOK, names[100]) //訪問(wèn)不到 }) r.Run(":9999") }
你也許會(huì)問(wèn)為什么實(shí)現(xiàn)的這么繁瑣,那么下文將會(huì)解釋下原因!
外鏈:http://www.dbjr.com.cn/article/237709.htm
跨域測(cè)試:
失敗情況:
成功情況!
到此這篇關(guān)于Go中跨域Cors中間件的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)Go跨域Cors中間件內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Go與Redis實(shí)現(xiàn)分布式互斥鎖和紅鎖
這篇文章主要介紹了Go與Redis實(shí)現(xiàn)分布式互斥鎖和紅鎖,文章圍繞主題展開(kāi)詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下2022-09-09goland?導(dǎo)入github包報(bào)紅問(wèn)題解決
本文主要介紹了Go項(xiàng)目在GoLand中導(dǎo)入依賴標(biāo)紅問(wèn)題解決,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2024-08-08golang獲取prometheus數(shù)據(jù)(prometheus/client_golang包)
本文主要介紹了使用Go語(yǔ)言的prometheus/client_golang包來(lái)獲取Prometheus監(jiān)控?cái)?shù)據(jù),具有一定的參考價(jià)值,感興趣的可以了解一下2025-03-03GO語(yǔ)言實(shí)現(xiàn)批量壓縮圖片和水印
這篇文章主要介紹了GO語(yǔ)言實(shí)現(xiàn)批量壓縮圖片和水印,主要用到了github.com/nfnt/resize這個(gè)第三方庫(kù),僅僅支持JPG圖片格式,有相同需求的小伙伴參考下吧。2015-03-03Go實(shí)現(xiàn)替換(覆蓋)文件某一行內(nèi)容的示例代碼
本文主要介紹了Go實(shí)現(xiàn)替換(覆蓋)文件某一行內(nèi)容的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-07-07Go語(yǔ)言實(shí)現(xiàn)超時(shí)的三種方法實(shí)例
超時(shí)在一些業(yè)務(wù)場(chǎng)景里非常普遍,下面這篇文章主要給大家介紹了關(guān)于Go語(yǔ)言實(shí)現(xiàn)超時(shí)的三種方法,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用Go語(yǔ)言具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2022-07-07解決go build不去vendor下查找包的問(wèn)題
這篇文章主要介紹了解決go build不去vendor下查找包的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-12-12