Go实现跨域Cors中间件

news2024/12/28 18:50:43

概述

本版本主要实现cors中间件
github 地址:Sgin 欢迎star,将会逐步实现一个go web框架

内容

通过建造者模式创建我们的跨域中间件Cors \

我们了解到,当使用XMLHttpRequest发送请求时,如果浏览器发现违反了同源策略就会自动加上一个请求头 origin;
后端在接受到请求后确定响应后会在 Response Headers 中加入一个属性 Access-Control-Allow-Origin;
浏览器判断响应中的 Access-Control-Allow-Origin 值是否和当前的地址相同,匹配成功后才继续响应处理,否则报错\

缺点:忽略 cookie,浏览器版本有一定要求

同时,结合项目实际,我们可以使用一个config结构体来存放我们的配置,这里可以使用建造者模式进行灵活的管理
所以cors中,我们也添加与config相同的字段
Config:

// CorsConfig 使用了建造者模式
type CorsConfig struct {
	AllowOrigins []string
	AllowMethods []string
	AllowHeaders []string
	//如果想要让客户端可以访问到其他的标头,服务器必须将它们在 Access-Control-Expose-Headers 里面列出来.eg:"Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers,Cache-Control,Content-Language,Content-Type,Expires
	ExposeHeaders []string
	//这个响应头表示 preflight request (预检请求)的返回结果(即 Access-Control-Allow-Methods 和Access-Control-Allow-Headers 提供的信息)可以被缓存多久。
	AccessControlMaxAge string
	//告知浏览器是否可以将对请求的响应暴露给前端 JavaScript 代码。
	AccessControlAllowCredentials bool
}

Cors:

type Cors struct {
AllowOrigins []string
AllowMethods []string
AllowHeaders []string
//如果想要让客户端可以访问到其他的标头,服务器必须将它们在 Access-Control-Expose-Headers 里面列出来.eg:"Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers,Cache-Control,Content-Language,Content-Type,Expires
ExposeHeaders []string
//这个响应头表示 preflight request (预检请求)的返回结果(即 Access-Control-Allow-Methods 和Access-Control-Allow-Headers 提供的信息)可以被缓存多久。
AccessControlMaxAge string
//告知浏览器是否可以将对请求的响应暴露给前端 JavaScript 代码。
AccessControlAllowCredentials bool
}

当然,我们的Config需要一些方法来控制字段的值


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
}

同时,为了方便,我们可以给出一个方法来设置默认的情况

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,
   }
}

最后,实现将config应用到Cors中的方法和应用Cors的设置的方法
将config应用到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
}

应用Cors的设置的方法 :

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, ",")) // 设置允许访问所有域
   		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!")
   	}
   	//处理请求
   	context.Next()
   }
}

当然,我们提供快速开始的方案:

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]) //访问不到
	})

	r.Run(":9999")
}


你也许会问为什么实现的这么繁琐,那么下文将会解释下原因!
外链:https://zhuanlan.zhihu.com/p/58093669
跨域测试:
失败情况:
失败情况

成功情况!
成功情况!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/605928.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

StableDiffusion入门教程

目录 介绍模型的后缀ckpt模型&#xff1a;safetensors模型文件夹VAE 模型在哪下载Hugging face:<https://huggingface.co/models>下载SD官方模型文生图模型标签介绍 C站&#xff1a;<https://civitai.com/>筛选模型的类型CheckPoint Type &#xff08;模型的类型&a…

Python学习笔记 - 探索元组Tuple的使用

欢迎各位&#xff0c;我是Mr数据杨&#xff0c;你们的Python导游。今天&#xff0c;我要为大家讲解一段特殊的旅程&#xff0c;它与《三国演义》有关&#xff0c;而我们的主角是元组&#xff08;tuple&#xff09;。 让我们想象这样一个场景&#xff0c;三国演义中的诸葛亮&am…

pandas数据预处理

pandas数据预处理 pandas及其数据结构pandas简介Series数据结构及其创建DataFrame数据结构及其创建 利用pandas导入导出数据导入外部数据导入数据文件 导出外部数据导出数据文件 数据概览及预处理数据概览分析利用DataFrame的常用属性利用DataFrame的常用方法 数据清洗缺失值处…

Cesium教程 (3) 矢量切片mvt-imagery-provider加载

Cesium教程 (3) 矢量切片mvt-imagery-provider加载 目录 0. 矢量切片 1. 开源项目 2. 环境 3. 代码 4. TODO 0. 矢量切片 WMTS&#xff1a;加载最快&#xff0c;图片格式&#xff0c;样式固定&#xff1b; WMS&#xff1a;加载数量大则慢&#xff0c;但可以点击查询等&am…

htmlCSS-----CSS选择器(上)

目录 前言&#xff1a; 1.初级选择器 &#xff08;1&#xff09;ID选择器 &#xff08;2&#xff09;class选择器 &#xff08;3&#xff09;标签选择器 &#xff08;4&#xff09;通配选择器 前言&#xff1a; CSS选择器是CSS页面处理的重要组成部分&#xff0c;前面讲到…

MMPose关键点检测实战

安装教程 https://github.com/TommyZihao/MMPose_Tutorials/blob/main/2023/0524/%E3%80%90A1%E3%80%91%E5%AE%89%E8%A3%85MMPose.ipynb git clone https://github.com/open-mmlab/mmpose.git -b tutorial2023 -b代表切换到某个分支&#xff0c;保证分支和作者的教程一致 ra…

基于SpringBoot+Thymeleaf+Mybatis+Html校园二手交易平台

基于SpringBootThymeleafMybatisHtml校园二手交易平台 一、系统介绍1、系统主要功能&#xff1a;2、环境配置 二、功能展示1.主页(客户)2.登陆&#xff08;客户&#xff09;3.我的购物车(客户)4.我的订单&#xff08;客户&#xff09;5.主页&#xff08;管理员&#xff09;6.订…

mybatisplus数据权限插件学习初探 动态表名更换插件 防止全表更新与删除插件

文章目录 学习链接 mybatisplus数据权限插件学习初探前言案例建表用户表订单表 环境准备UserUserMapperUserMapper.xmlOrdersOrdersMapperOrdersMapper.xml 配置UserTypeEnumUserContextHolderCustomizeDataPermissionHandlerMybatisPlusConfig 测试测试类bossdeptManagerclerk…

Redis通信协议、过期回收策略

Redis通信协议-RESP协议 Redis是一个CS架构的软件&#xff0c;通信一般分两步&#xff08;不包括pipeline和PubSub&#xff09;&#xff1a; 客户端&#xff08;client&#xff09;向服务端&#xff08;server&#xff09;发送一条命令 服务端解析并执行命令&#xff0c;返回…

二级指针骚操作实现链表虚拟头节点

重点是不用像其他文章里那样&#xff0c;用一个普通节点成员变量当头节点&#xff0c;节省一点空间占用&#xff0c;反正我觉得有点骚。就不详细交代技术背景了&#xff0c;简而言之&#xff0c;就是链表中第一个节点前没有节点了&#xff0c;只有一个指向它的指针&#xff0c;…

强化学习基础篇[3]:DQN、Actor-Critic详解

【强化学习原理+项目专栏】必看系列:单智能体、多智能体算法原理+项目实战、相关技巧(调参、画图等、趣味项目实现、学术应用项目实现 专栏详细介绍:【强化学习原理+项目专栏】必看系列:单智能体、多智能体算法原理+项目实战、相关技巧(调参、画图等、趣味项目实现、学术应…

从实习到秋招成为一名安全工程师,我是怎么做的

前言 借朋友口述总结了安全招聘面试经历分享&#xff0c;希望更多的人看到这篇文&#xff0c;从中得到启发&#xff0c;找到自己心仪的工作。 基本情况 签了字节的三方&#xff0c;秋招终于告一段落。从八月份边实习边准备秋招到现在&#xff0c;经历了许多&#xff0c;这篇帖…

Linux :: 【简单开发篇 :: vim 编辑器:(1)】:: vim 编辑器的基本认识与三种 vim 常用模式 | 使用:打开编辑、退出保存关闭vim

前言&#xff1a;本篇是 Linux 基本操作篇章的内容&#xff01; 笔者使用的环境是基于腾讯云服务器&#xff1a;CentOS 7.6 64bit。 学习集&#xff1a; C 入门到入土&#xff01;&#xff01;&#xff01;学习合集Linux 从命令到网络再到内核&#xff01;学习合集 目录索引&am…

yolov8Pose实战

目录 前言一、yolov8环境搭建二、测试训练模型&#xff0c;评估模型&#xff0c;并导出模型实测检测效果 测试人体姿态估计 前言 YOLO系列层出不穷&#xff0c;从yolov5到现在的yolov8仅仅不到一年的时间。追踪新技术&#xff0c;了解前沿算法&#xff0c;一起来测试下yolov8在…

【密码学复习】第十章 身份鉴别

身份鉴别的定义 定义&#xff1a;身份鉴别&#xff0c;又称为身份识别、身份认证。它是证实客户的真实身份与其所声称的身份是否相符的过程。 口令身份鉴别 固定口令&#xff08;四&#xff09; 注册环节&#xff1a;双因子认证 ① 接收用户提供的口令pw&#xff08;PIN&…

车辆救援道路救援预约汽修托运小程序

道路救援&#xff1a;指汽车道路紧急救援&#xff0c;为故障车主提供包括诸如&#xff1a;拖吊、换水、充电、换胎、送油以及现场小修等服务(Road-Side Service)&#xff1b; 同时也指交通事故道路救援&#xff0c;包括伤员救治、道路疏导等。 随着我国巨大的汽车拥有量&…

1计算机系统概述_1.2计算机系统层次结构

1.2 计算机系统层次结构 计算机系统&#xff08;CO 自命名&#xff09; 1、CO的组成 硬件系统和软件系统共同构成了一个完整的计算机系统 ——硬件&#xff1a;有形的物理设备&#xff0c;是CO中实际物理装置的总称 ——软件&#xff1a;在硬件上运行的程序和相关的数据及文…

SpringCloud:分布式缓存之Redis哨兵

Redis提供了哨兵&#xff08;Sentinel&#xff09;机制来实现主从集群的自动故障恢复。 1.哨兵原理 1.1.集群结构和作用 哨兵的结构如图&#xff1a; 哨兵的作用如下&#xff1a; 监控&#xff1a;Sentinel会不断检查您的master和slave是否按预期工作自动故障恢复&#xff…

人工智能(pytorch)搭建模型9-pytorch搭建一个ELMo模型,实现训练过程

大家好&#xff0c;我是微学AI&#xff0c;今天给大家介绍一下人工智能(pytorch)搭建模型9-pytorch搭建一个ELMo模型&#xff0c;实现训练过程&#xff0c;本文将介绍如何使用PyTorch搭建ELMo模型&#xff0c;包括ELMo模型的原理、数据样例、模型训练、损失值和准确率的打印以及…

labelimg闪退解决方法(之前使用过labelimg,但新一次使用,打开文件夹无反应,再次打开闪退的问题)及标注经验

问题描述&#xff1a; 之前使用过labelimg进行好多次的标注&#xff0c;但新一次运行使用&#xff0c;发现打开目录无反应&#xff0c;再次打开闪退的问题&#xff0c;重启电脑并且从新运行labelimg仍然无效。 解决方法&#xff1a; 关闭labelimg&#xff0c;然后删除文件C…