GIN 反向代理功能

今天想试着做一个gin的反向代理,代理其他的服务,给前端使用,思路如下:

主要组成部分

  1. 跨域中间件(Cors 函数)

    • Cors 中间件函数通过在 HTTP 响应中设置合适的头部信息,允许跨域请求。
    • 它添加了允许的方法(例如 POSTGETOPTIONS 等),并向客户端公开特定的头部字段。
    • 对于预检请求(即 OPTIONS 请求),直接返回 “ok” 表示请求被允许。
    • 还包含一个 defer 函数,用于在发生 panic 时进行恢复处理。
  2. 反向代理中间件(ReverseProxy 函数)

    • ReverseProxy 函数将传入的请求转发到由 targetURL 指定的目标服务器。
    • 使用 httputil.NewSingleHostReverseProxy 为指定目标创建一个反向代理。
    • 调整请求的 host 和 URL,使其与目标服务器匹配,以确保请求被正确转发。
  3. 动态更新目标 URL(UpdateTargetURL 函数)

    • 该端点(/api/update-target)用于更新反向代理所使用的 targetURL,这是一个受读写锁保护的全局变量。
    • 接收包含 hostport 值的 JSON 负载,以设置新的目标 URL。
    • 更新后的 targetURL 会被格式化并存储,然后返回一个确认消息。
  4. 服务器启动函数(Start 函数)

    • Start 函数根据配置的模式(debug 或 release)初始化 Gin 服务器。
    • 全局应用 CORS 中间件,并设置一个用于更新目标 URL 的端点。
    • 设置反向代理路由,将 /v1/*proxyPath 下的所有请求转发到当前目标 URL。
    • 服务器监听并在端口 8080 上运行。

功能要求

  • 并发和安全性:通过使用 mu 锁,确保对 targetURL 的线程安全访问,因为多个 goroutine 可能同时读取或更新此值。
  • 错误处理UpdateTargetURL 函数处理格式不正确的 JSON 请求,如果输入的 JSON 无效,则返回 400 Bad Request
  • 可配置的代理目标:允许动态更新 targetURL 使该服务器设置更灵活,可以根据需要将请求路由到不同的后端服务器。
  • 调试:在 Start 中检查配置的详细模式,以根据需要设置 Gin 的 debug 或 release 模式,用于在生产与开发环境中切换日志记录。

此设置非常适合需要将请求动态代理到不同后端服务器的场景,同时处理跨域请求并确保并发访问的安全性。

代码实现
package webimport ("fmt""net/http""net/http/httputil""net/url""sync""github.com/gin-gonic/gin""client/backend/internal/config"
)var (targetURL string       = "http://127.0.0.1:8080" // Default target URLmu        sync.RWMutex                              // Mutex for safe concurrent access
)// 跨域中间件
func Cors() gin.HandlerFunc {return func(c *gin.Context) {method := c.Request.Methodorigin := c.Request.Header.Get("Origin") //请求头部if origin != "" {//接收客户端发送的origin (重要!)c.Writer.Header().Set("Access-Control-Allow-Origin", origin)//服务器支持的所有跨域请求的方法c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE,UPDATE")//允许跨域设置可以返回其他子段,可以自定义字段c.Header("Access-Control-Allow-Headers", "Content-Type,Authorization, Content-Length, X-CSRF-Token, Token,session")// 允许浏览器(客户端)可以解析的头部 (重要)c.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers")//设置缓存时间c.Header("Access-Control-Max-Age", "172800")//允许客户端传递校验信息比如 cookie (重要)c.Header("Access-Control-Allow-Headers", "Origin, Content-Type, Accept, Authorization, X-Requested-With")c.Header("Access-Control-Allow-Credentials", "true")}//允许类型校验if method == "OPTIONS" {c.JSON(http.StatusOK, "ok!")}defer func() {if err := recover(); err != nil {fmt.Println("Panic info is: %v", err)}}()c.Next()}
}// ReverseProxy function to forward requests to the target server.
// ReverseProxy function to forward requests to the current target server.
func ReverseProxy() gin.HandlerFunc {return func(c *gin.Context) {mu.RLock() // Lock for readingdefer mu.RUnlock()target, err := url.Parse(targetURL)if err != nil {c.JSON(http.StatusInternalServerError, gin.H{"error": "Invalid target URL"})return}proxy := httputil.NewSingleHostReverseProxy(target)// Update the request to the target URLc.Request.Host = target.Hostc.Request.URL.Host = target.Hostc.Request.URL.Scheme = target.Scheme// Serve the request using the reverse proxyproxy.ServeHTTP(c.Writer, c.Request)}
}type BackendServer struct {Host string `json:"host"`Port int    `json:"port"`
}// UpdateTargetURL updates the target URL dynamically.
func UpdateTargetURL(c *gin.Context) {var options BackendServer// Bind the JSON body to the newTarget structif err := c.ShouldBindJSON(&options); err != nil {c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request body", "code": 400})return}mu.Lock() // Lock for writingdefer mu.Unlock()// Update the global targetURL variabletargetURL = fmt.Sprintf("%s:%d", options.Host, options.Port)c.JSON(http.StatusOK, gin.H{"message": "Target URL updated", "new_target": targetURL, "code": 200})
}
func Start() {if config.C().Verbose {gin.SetMode(gin.DebugMode)} else {gin.SetMode(gin.ReleaseMode)}router := gin.Default()router.Use(Cors())// Route to update the target server URLrouter.POST("/api/update", UpdateTargetURL)// Proxy all requests to the /api endpoint to the current target serverrouter.Any("/v1/*proxyPath", ReverseProxy())// Run the Gin server on port 8080if err := router.Run(":8080"); err != nil {panic(err)}
}

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Unity计算二维向量夹角余弦值和正弦值的优化方法参考

如果不考虑优化问题,计算两个向量的余弦值或者正弦值可以直接使用类似的方法: [SerializeField] Vector2 v1, v2;void Start() {float valCos Mathf.Acos(Vector2.SignedAngle(v1, v2));float valSin Mathf.Asin(Vector2.SignedAngle(v1, v2)); } 但是…

深度|谁在为OpenAI和Anthropic的AI编程竞赛提供“军火”?已赚得盆满钵满

图片来源:Unsplash AI 开发者之所以一致认为编程的重要性,是有原因的:大型语言模型编程能力越强,它回答与软件无关的其他类型问题的能力也越强。 去年秋天,几位 Google 人工智能领导者与初创公司 CEO Jonathan Siddh…

2024年北京市安全员-A证证模拟考试题库及北京市安全员-A证理论考试试题

题库来源:安全生产模拟考试一点通公众号小程序 2024年北京市安全员-A证证模拟考试题库及北京市安全员-A证理论考试试题是由安全生产模拟考试一点通提供,北京市安全员-A证证模拟考试题库是根据北京市安全员-A证最新版教材,北京市安全员-A证大…

[ 问题解决篇 ] win11中本地组策略编辑器gpedit.msc打不开(gpedit.msc缺失)

🍬 博主介绍 👨‍🎓 博主介绍:大家好,我是 _PowerShell ,很高兴认识大家~ ✨主攻领域:【渗透领域】【数据通信】 【通讯安全】 【web安全】【面试分析】 🎉点赞➕评论➕收藏 养成习…

前端聊天室页面开发(赛博朋克科技风,内含源码)

肝了一天,经过各种处理美化,肝出来了一个赛博朋克科技风的前端页面,用的原生三件套htmlcssjavascript开发的,本来想是加点功能调用一下gpt接口,但是基本都需要webscoket通信,可惜我js学的不是很深入&#x…

TMDOG的Gin学习笔记_01——初识Gin框架

TMDOG的Gin学习笔记_01——初识Gin框架 博客地址:[TMDOG的博客](https://blog.tmdog114514.icu) 作者自述: 停更太久了,是因为开学了课太多了,并且我一直在准备上篇文章的内容正在coding,就先搁置了更新博客QAQ&…

wsl2.0(windows linux子系统)使用流程

1.什么是wsl wsl指的是windows的linux子系统,最初是wsl1.0,靠windows内核来模拟linux内核,并不运行真正的linux内核,所以有时会有兼容性的问题。 而wsl2.0是基于windows自带的虚拟机功能hyper-v的,它会把设备上的每个…

计算机网络:网络层 —— IPv4 数据报的首部格式

文章目录 IPv4数据报的首部格式IPv4数据报分片生存时间 TTL字段协议字段首部检验和字段 IPv4数据报的首部格式 IPv4 数据报的首部格式及其内容是实现 IPv4 协议各种功能的基础。 在 TCP/IP 标准中,各种数据格式常常以32比特(即4字节)为单位来描述 固定部分&#x…

vue3学习记录-nextTick

vue3学习记录-nextTick 1. 案例场景2. 使用方法2.1 回调方式2.2 async&#xff0c;await 3.原理 1. 案例场景 聊天框实现输入内容&#xff0c;滚动条默认滚到最底部。 <template><div class"chat_box"><div class"chat_list" ref"chat…

Facebook群控策略详解

Facebook群控早在前几年就很火爆了&#xff0c;对于做Facebook营销或者电商的跨境选手来说&#xff0c;这是个不错的提高效率扩大增长的办法。具体来说&#xff0c;Facebook群控是一种通过同时管理多个Facebook账户进行自动化推广活动的方法&#xff0c;它可以实现自动发布帖子…

【私聊记录】最近在忙什么啊?听说你在学人工智能?

小舒&#xff1a;哎&#xff0c;你最近在忙什么啊&#xff1f; 小元&#xff1a;我在学习人工智能呢。 小舒&#xff1a;人工智能&#xff1f;难不难学啊&#xff1f; 小元&#xff1a;不难&#xff0c;找到正确的学习姿势就不难了&#xff01; 小舒&#xff1a;那你为什么想学…

BLE 协议之 L2CAP

目录 一、简介二、L2CAP Protocol 架构1、逻辑信道划分2、信道模式3、设计思想4、帧结构4.1 面向连接信道 B-frame4.2 无连接数据信道包 G-frame4.3 重传/流量控制/流传输模式下的面向连接的信道 S-frame、I-frame4.4 面向连接的通道分为 LE 信用流控模式和增强型信用流控模式 …

『 Linux 』网络传输层 - TCP(二)

文章目录 TCP六个标志位TCP的连接三次握手 四次挥手为什么是三次握手和四次挥手 重传机制 TCP六个标志位 在TCP协议报文的报头中存在一个用于标志TCP报文类型的标志位(不考虑保留标志位),这些标志位以比特位选项的方式存在,即对应标志位为0则表示为假,对应标志位为1则为真; SYN…

安科瑞AMB400分布式光纤测温系统解决方案--远程监控、预警,预防电气火灾

安科瑞戴婷 可找我Acrel-Fanny 安科瑞AMB400电缆分布式光纤测温具有多方面的特点和优势&#xff1a; 工作原理&#xff1a; 基于拉曼散射效应。激光器产生大功率的光脉冲&#xff0c;光在光纤中传播时会产生散射。携带有温度信息的拉曼散射光返回光路耦合器&#xff0c;耦…

Raspberry Pi 树莓派产品系列说明

系列文章目录 前言 随着我们产品线的不断扩展&#xff0c;要了解所有不同的 Raspberry Pi 板可能会让人感到困惑。以下是 Raspberry Pi 型号的高级分类&#xff0c;包括我们的旗舰系列、Zero 系列、计算模块系列和 Pico 微控制器。 Raspberry Pi 电脑分为几个不同的系列&#x…

电阻电容电感为什么通常是10、22、47这些数

电阻电容电感为什么通常是10、22、47这些数 优先数的来源优先数的优点&#xff1a;E24和E96的来源 我们在选择电阻时&#xff0c;经常看到的阻值是33Ohm&#xff0c;4.7KOhm&#xff0c;1KOhm&#xff0c;680Ohm.基本上是以这几个数字开头。 同时在选择电容时&#xff0c;经常看…

以「JIMUMETA元宇宙体验馆」为例,探讨有哪些元宇宙场景?

让我们以「JIMUMETA元宇宙体验馆」为例&#xff0c;深入探讨元宇宙场景中提供的产品与服务。该体验馆由视创云展精心打造&#xff0c;集成了企业主展馆、元宇宙虚拟活动分会场、品牌展示分会场、线上论坛会场以及会议室接待会客等多重功能&#xff0c;旨在全方位满足企业发布会…

在MacOS玩RPG游戏 - RPGViewerPlus

背景知识 由于我一直使用Mac电脑&#xff0c;所以一直对Mac如何玩RPGMV/RPGMZ游戏的方式有进一步的想法。 网上能给出的方案都是自行启动一个HTTP服务进行&#xff0c;进行服务加载。这个方法有效&#xff0c;但兼容性较差。涉及到自定义功能模块的游戏&#xff0c;都会有报错…

使用Scrapy框架爬取博客信息

随着网络的发展&#xff0c;越来越多有价值的信息存储在网络上。使用爬虫技术可以从这些信息源中提取出有用的数据。本文将介绍如何使用Python中的Scrapy框架来爬取博客站点上的文章标题、作者以及阅读数&#xff0c;并将其保存到JSON文件中。 一、项目背景 Scrapy是一个快速…

【Java Web】使用JDBC操作数据库(含代码示例)

文章目录 JDBC主要组成部分访问数据库步骤数据库交互StatementPreparedStatementSQL注入攻击 演示示例单查询多查询返回记录数 JDBC&#xff08;Java Database Connectivity&#xff09;是Java中用于执行SQL语句的标准API&#xff0c;它提供了一种统一的方式来访问各种关系型数…