Go实现CORS(跨域)

引言

很多时候,需要允许Web应用程序在不同域之间(跨域)实现共享资源。本文将简介跨域、CORS的概念,以及如何在Golang中如何实现CORS。

什么是跨域

如果两个 URL 的协议、端口(如果有指定的话)和主机都相同的话,则这两个 URL 是同源的。例如

URL 结果 原因
store.company.com/dir2/other.... 同源 只有路径不同
store.company.com/dir/inner/a... 同源 只有路径不同
store.company.com/secure.html 失败 协议不同
store.company.com:81/dir/etc.htm... 失败 端口不同(http:// 默认端口是 80)
store.company.com:81/dir/etc.htm... 失败 主机不同

什么是CORS

跨域资源共享(Cross-origin resource sharing,CORS),用于让网页的受限资源能够被其他域名的页面访问的一种机制。通过该机制,页面能够自由地使用不同源的图片、样式、脚本、iframes以及视频。一些跨域的请求(特别是Ajax)常常会被同源策略(Same-origin policy)所禁止。跨源资源共享定义了一种方式,为的是浏览器和服务器之间能互相确认是否足够安全以至于能使用跨源请求(cross-origin requests)。比起纯粹的同源请求,这将更为自由和功能性的(functionality),但比纯粹的跨源请求更为安全。---维基百科

实现原理

跨域资源共享标准描述了,新的HTTP头部在浏览器有权限的时候,应该以如何的形式发送请求到远程URLs。虽然服务器会有一些校验和认证,但是浏览器有责任去支持这些头部以及增加相关的限制。对于能够修改数据的Ajax和HTTP请求方法(特别是 GET 以外的 HTTP 请求,或者搭配某些 MIME 类型的 POST 请求),浏览器必须首先使用 OPTIONS 方法发起一个预检请求(preflight request),从而获知服务端是否允许该跨源请求。服务器确认允许之后,才发起实际的 HTTP 请求。在预检请求的返回中,服务器端也可以通知客户端,是否需要携带身份凭证(包括 Cookies 和 HTTP 认证相关数据)。

Go是如何实现

在Golang中,可以使用HTTP处理程序和中间件来实现CORS。接着我们以Gin为例

go 复制代码
package main

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

func main() {
	router := gin.Default()

	// CORS中间件
	cors := func(c *gin.Context) {
		// 允许特定的域进行跨域请求
		c.Writer.Header().Set("Access-Control-Allow-Origin", "http://mysite.vip")
		// 允许特定的请求方法
		c.Writer.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE")
		// 允许特定的请求头
		c.Writer.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization")
		// 允许携带身份凭证(如Cookie)
		c.Writer.Header().Set("Access-Control-Allow-Credentials", "true")
		// 继续处理请求
		c.Next()
	}

	// 应用CORS中间件到所有路由
	router.Use(cors)

	// 定义一个路由和处理器函数
	router.GET("/hello-world", func(c *gin.Context) {
		c.String(http.StatusOK, "Hello, World!")
	})
	router.Run(":8080")
}

输出

csharp 复制代码
[GIN-debug] GET /hello-world --> main.main.func2 (4 handlers)
[GIN-debug] Listening and serving HTTP on :8080

在上例中,设置了Access-Control-Allow-Origin响应头,指定允许跨域请求的域名。您可以根据需要设置为特定域名、通配符*(允许所有域名)或动态获取请求头中的Origin值。另外,还设置了允许的请求方法、请求头以及是否允许携带身份凭证(如Cookie)。

测试

这里通过命令行curl来验证,如果返回结果中出现 CORS 相关的 header( ccess-Control-Allow-Origin: * < Access-Control-Allow-Methods: * < Access-Control-Allow-Headers: * < Access-Control-Expose-Headers: * < Access-Control-Max-Age: 5 ),则跨域成功。结果如下:

cmd 复制代码
#curl -i -k http://127.0.0.1:8080/hello-world
HTTP/1.1 200 OK
Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Origin: http://mysite.vip
Content-Type: text/plain; charset=utf-8
Date: Sat, 14 Oct 2023 13:42:35 GMT
Content-Length: 13

Hello, World!

Success

参考

相关推荐
梁梁梁梁较瘦17 小时前
边界检查消除(BCE,Bound Check Elimination)
go
梁梁梁梁较瘦18 小时前
指针
go
梁梁梁梁较瘦18 小时前
内存申请
go
半枫荷18 小时前
七、Go语法基础(数组和切片)
go
梁梁梁梁较瘦1 天前
Go工具链
go
半枫荷2 天前
六、Go语法基础(条件控制和循环控制)
go
半枫荷3 天前
五、Go语法基础(输入和输出)
go
小王在努力看博客3 天前
CMS配合闲时同步队列,这……
go
Anthony_49263 天前
逻辑清晰地梳理Golang Context
后端·go
Dobby_054 天前
【Go】C++ 转 Go 第(二)天:变量、常量、函数与init函数
vscode·golang·go