配置gin框架支持跨域請求


一、使用cors解決跨域問題

CORS(Cross-origin resource sharing,跨域資源共享)是一個 W3C 標准,定義了在必須訪問跨域資源時,瀏覽器與服務器應該如何溝通。CORS 背后的基本思想,就是使用自定義的 HTTP 頭部讓瀏覽器與服務器進行溝通,從而決定請求或響應是應該成功,還是應該失敗。CORS 需要瀏覽器和服務器同時支持。

整個CORS通信過程,都是瀏覽器自動完成,不需要用戶參與。對於開發者來說,CORS通信與同源的AJAX通信沒有差別,代碼完全一樣。瀏覽器一旦發現AJAX請求跨源,就會自動添加一些附加的頭信息,有時還會多出一次附加的請求,但用戶不會有感覺。

瀏覽器將CORS請求分成兩類:簡單請求(simple request)和非簡單請求(not-so-simple request)。

1. 簡單請求

簡單請求是指滿足下面兩大條件的請求:

  • 請求方法為 HEAD、GET、POST中的一種。
  • HTTP頭信息不超過一下幾種:
    • Accept
    • Accept-Language
    • Content-Language
    • Last-Event-ID
    • Content-Type(只限於三個值application/x-www-form-urlencodedmultipart/form-datatext/plain

對於簡單請求,瀏覽器回自動在請求的頭部添加一個 Origin 字段來說明,本子請求來自那個源(協議 + 域名 + 端口),服務端則通過這個值判斷是否接收本次請求。如果 Origin 在許可范圍內,則服務器返回的響應會多出幾個頭信息:

Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers: Content-Type, Content-Length
Access-Control-Allow-Origin: *
Content-Type: text/html; charset=utf-8

我們就是通過配置這些參數來處理跨域請求的,下面會做詳細介紹。

2. 非簡單請求

非簡單請求是那種對服務器有特殊要求的請求,比如請求方法是 PUTDELETE ,或者 Content-Type 字段的類型是 application/json

非簡單請求的CORS請求,會在正式通信之前,增加一次HTTP查詢請求,稱為"預檢"請求(preflight)。

預檢請求其實就是我們常說的 OPTIONS 請求,表示這個請求是用來詢問的。頭信息里面,關鍵字段 Origin ,表示請求來自哪個源,除 Origin 字段,"預檢"請求的頭信息包括兩個特殊字段:

  • Access-Control-Request-Method

    該字段是必須的,用來列出瀏覽器的CORS請求會用到哪些HTTP方法
    
  • Access-Control-Request-Headers

    該字段是一個逗號分隔的字符串,指定瀏覽器CORS請求會額外發送的頭信息字段.
    

瀏覽器先詢問服務器,當前網頁所在的域名是否在服務器的許可名單之中,以及可以使用哪些HTTP動詞和頭信息字段。只有得到肯定答復,瀏覽器才會發出正式的 XMLHttpRequest 請求,否則就報錯。

3. 配置 CORS 解決跨域問題

上面我們了解了兩種跨域請求,其中出現了幾種特殊的 Header 字段,CORS 就是通過配置這些字段來解決跨域問題的,下面詳細介紹一下這些字段的含義:

(1)Access-Control-Allow-Origin

該字段是必須的。它的值要么是請求時Origin字段的值,要么是一個*,表示接受任意域名的請求。

(2)Access-Control-Allow-Methods

該字段必需,它的值是逗號分隔的一個字符串,表明服務器支持的所有跨域請求的方法。注意,返回的是所有支持的方法,而不單是瀏覽器請求的那個方法。這是為了避免多次"預檢"請求。

(3)Access-Control-Allow-Headers

如果瀏覽器請求包括Access-Control-Request-Headers字段,則Access-Control-Allow-Headers字段是必需的。它也是一個逗號分隔的字符串,表明服務器支持的所有頭信息字段,不限於瀏覽器在"預檢"中請求的字段。

(4)Access-Control-Expose-Headers

該字段可選。CORS請求時,XMLHttpRequest對象的getResponseHeader()方法只能拿到6個基本字段:Cache-ControlContent-LanguageContent-TypeExpiresLast-ModifiedPragma。如果想拿到其他字段,就必須在Access-Control-Expose-Headers里面指定。

(5)Access-Control-Allow-Credentials

該字段可選。它的值是一個布爾值,表示是否允許發送Cookie。默認情況下,Cookie不包括在CORS請求之中。設為true,即表示服務器明確許可,Cookie可以包含在請求中,一起發給服務器。這個值也只能設為 true,如果服務器不要瀏覽器發送Cookie,刪除該字段即可。

(6)Access-Control-Max-Age

該字段可選,用來指定本次預檢請求的有效期,單位為秒,在此期間,不用發出另一條預檢請求。

二、示例代碼

gin框架寫的http接口支持跨域請求的方法很簡單,實現一個支持跨域的中間件接口就行,關鍵代碼如下:

package main

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

func Cors() gin.HandlerFunc {
	return func(c *gin.Context) {
		origin := c.Request.Header.Get("origin")	//請求頭部
		if len(origin) == 0 {
			origin = c.Request.Header.Get("Origin")
		}
		//接收客戶端發送的origin (重要!)
		c.Writer.Header().Set("Access-Control-Allow-Origin", origin)
		//允許客戶端傳遞校驗信息比如 cookie (重要)
		c.Writer.Header().Set("Access-Control-Allow-Credentials", "true")
		c.Writer.Header().Set("Access-Control-Allow-Headers", "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, accept, origin, Cache-Control, X-Requested-With")
		//服務器支持的所有跨域請求的方法
		c.Writer.Header().Set("Access-Control-Allow-Methods", "OPTIONS, GET, POST, PUT, DELETE, UPDATE")
		c.Writer.Header().Set("Content-Type", "application/json; charset=utf-8")
        // 設置預驗請求有效期為 86400 秒
		c.Writer.Header().Set("Access-Control-Max-Age", "86400")
		if c.Request.Method == "OPTIONS" {
			c.AbortWithStatus(204)
			return
		}
		c.Next()
	}
}

func statusOKHandler(c *gin.Context) {
	c.JSON(http.StatusOK, gin.H{"msg": "success"})
}


func main() {
	r := gin.Default()
	r.Use(Cors())

	r.GET("/hello", statusOKHandler)
	r.Run(":9000")
}

如果要調整一些跨域的規則,則修改cors方法里的一些相關參數即可。

參考1

參考2


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM