基于 Gin 的 HTTP 代理 demo

上次用 TCP 模拟了一个 HTTP 代理之后,感觉那样还是太简陋了,想着是不是可以用框架来做一个有点实际用处的东西。所以,就思索如何用 golang 的 Gin 框架来实现一个?嗯,对的你没有听错,是 gin 框架。你可能会疑惑,它不是 Web 框架吗,怎么可以用来做代理软件呢?哈哈,其实仔细想一想就明白了。我已经说过了,HTTP 代理的本质其实就是一个 HTTP 服务器!所以,我只要想办法让它来处理所有的路由就行了!

经过思考之后,我想到了 404 这个东西,通常对于一个 Web 服务来说,它就是不存在的路由。也就是说:
存在的路由 + 不存在的路由 = 全部的路由
对于一个 Web 服务,我们是有明确的接口(路由)的,所以会定义很多存在的路由。但是对于一个代理服务器来说,它根本不关心你的路由是什么,也就不需要存在的路由(你根本不知道用户会访问哪些路由),所以我们只需要处理不存在的路由即可。这里不存在的路由是指,不被 Web 服务处理的路由。
这样描述可能会有些困惑,那么就直说好了,我的想法是:在 Gin 框架中,不定义路由,这样全部的路由都会被认为是不存在的路由了,然后在专门处理 404 的方法中对所有的路由进行处理。相当于通过一个巧妙的方法,从而达到处理所有路由的目的,这样利用它来做一个 HTTP 代理就没有任何问题了。

代码

package mainimport ("fmt""io""log""net/http""strings""github.com/gin-gonic/gin"
)func main() {r := gin.Default()r.NoRoute(routeProxy)  // 路由代理 handlerr.GET("/", routeProxy) // 默认就有一个 / 路由,所以把它也在路由代理中处理r.Run(":8000")         // listen and serve on 0.0.0.0:8080 (for windows "localhost:8080")
}// 这样就可以处理所有的路由情况了
func routeProxy(c *gin.Context) {// 代理接收到请求将其发出,然后再返回对应的响应。req := c.Requestgo resolveReq(req) // 看看这个请求干了什么,注意不能代理自己,否则会有问题的newReq, _ := http.NewRequest(req.Method, req.URL.String(), req.Body)resp, err := http.DefaultClient.Do(newReq)if err != nil {log.Fatal(err)}defer resp.Body.Close()data, err := io.ReadAll(resp.Body)if err != nil {log.Fatal(err)}code := resp.StatusCodec.Status(code) // 响应状态码for k, v := range resp.Header {c.Header(k, strings.Join(v, ","))}c.Header("Server", "CrazyDragonHttpProxy") // 篡改一个响应回复c.Writer.Write(data)                       // 响应数据
}func resolveReq(req *http.Request) {fmt.Printf("Method: %s, Host: %s, URL: %s\n", req.Method, req.Host, req.URL.String())
}

注意:这里似乎也不需要这个默认的 /,因为代理的路由和不代理的路由是有区别的。

代理设置

请添加图片描述

这里 http=127.0.0.1,这样就只会代理 http 协议,不会处理 https 协议。因为我这里只是简单的 demo,我也不想去处理 https,那样太麻烦了,我也不是很了解具体怎么做。使用 Fiddler 进行抓包设置时,如果需要抓包 https 就需要安装它的证书,你就知道很麻烦了。

注意,它现在是一个代理服务器了,所以你不能访问它自己,不然就是代理服务器代理自己了。这里没对这个做处理,所以就会报错。

请添加图片描述

测试

现在想要找一个 http 的网站来测试真的是麻烦了,找了好久才发现一个 http 的网站,毕竟现在还用 http 的网站真的是太稀少了。

请添加图片描述

请添加图片描述

然后就出现问题了,我的电脑风扇开始狂啸,CPU 使用率飙升。然后就是打印上面这些东西了,所以应该就是代理服务器又把请求转发给了自己,然后系统可能就维持了大量的连接导致 CPU 使用率飙升。我开始以为是我的 http.DefaultClient 代码的问题,因为它的默认配置似乎会使用系统的代理。但是我又一想不对呀,因为我并不是在系统之中,我在容器里面呢!我现在把本地开发环境卸载了,所以我是在容器中进行开发的。不过,我又想到虽然我在容器中,但是 docker 还是在系统中的。

在这里插入图片描述

所以这个网络请求可能就是下图这样的:红色是用户请求,蓝色是代理的请求,它循环了,然后导致了问题。

在这里插入图片描述

所以,我又想了想,解决办法就是还是回到 Windows 本机上运行才行。但是因为本地已经没有了开发环境,所以再另辟蹊径,我只需要在 Windows 上执行就行了,并不需要在 Winwos 上面编译。所以让我们来交叉编译一个 Windows 的版本吧。
在这里插入图片描述

不过这玩意在 docker 容器里面呢,我还得拿出去才行,那怎么办才好呢?你听没有听过一个叫 docker cp 的命令!不过根本不需要那么麻烦,因为我这个目录是挂载进来的,我直接去我的挂载目录就行了,哈哈。

在这里插入图片描述
请添加图片描述

演示

终于是演示成功了,不过我发现它还是会因为无法处理 https 而终止(如果错误了,我就简单终止了程序,当然了你可以不处理直接返回就行了)。https 的那个 connect 方法,这玩意真的和乌云一样,正常的 web 开发用不到它,所以遇到了也就没法处理了(我只知道它是代理服务器建立隧道用的,其它的不清楚)。因为我前面那样设置,我以为是可以跳过 https 协议的,而且我的其它 https 页面是可以正常访问的,不过不知道为什么总有几个还是往代理服务器发送,它处理不了这个东西,导致代理崩溃了。

请添加图片描述

请添加图片描述

PS:
我刚开始在寻找那个循环请求的问题时,发现了一个老哥写的相似主题的文章。不过,他这个就早多了,好几年前了。不过,我这里最主要的想法是关于 404 的处理,他做的依然是关于指定路由的处理。不过,他使用那个工具直接发送请求还是值得参考的,但是因为这毕竟只是一个玩具,还是不宜过度深入为好,哈哈。

golang gin 代理和改包

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

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

相关文章

C语言——贪吃蛇

一. 游戏效果 贪吃蛇 二. 游戏背景 贪吃蛇是久负盛名的游戏,它也和俄罗斯⽅块,扫雷等游戏位列经典游戏的⾏列。 贪吃蛇起源于1977年的投币式墙壁游戏《Blockade》,后移植到各种平台上。具体如下: 起源。1977年,投币式…

链表的实现(文末附完整代码)

链表的概念及结构 链表是一种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的 我们在上一篇文章所学习的顺序表是连续存储的 例如: 顺序表就好比火车上的一排座位,是连续的 而链表就好比是火车…

Thinkphp8 - 连接多个数据库

// 数据库连接配置信息connections > [mysql > [// 数据库类型type > mysql,// 服务器地址hostname > 127.0.0.1,// 数据库名database > thinkphp,// 用户名username > env(DB_USER, root),// 密码password >…

计算机中丢失msvcr120.dll文件怎么修复?找不到msvcr120.dll五种完美修复方案

今天我想和大家分享的是关于“msvcr120.dll丢失的问题的5个解决方法”。在我们日常的工作生活中,或许大家都曾遇到过这样的问题,那么,了解它的解决方法是非常必要的。 首先,让我们来了解一下msvcr120.dll是什么文件。简单来说&am…

南昌大学漏洞报送证书

获取来源:edusrc(教育漏洞报告平台) url:https://src.sjtu.edu.cn/ 兑换价格:20金币 获取条件:南昌大学任意中危或以上级别漏洞

设计模式之十一:代理模式

代理可以控制和管理访问。 RMI提供了客户辅助对象和服务辅助对象,为客户辅助对象创建和服务对象相同的方法。RMI的好处在于你不必亲自写任何网络或I/O代码。客户程序调用远程方法就和运行在客户自己本地JVM对对象进行正常方法调用一样。 步骤一:制作远程…

【数据结构】树与二叉树(十二):二叉树的递归创建(算法CBT)

文章目录 5.2.1 二叉树二叉树性质引理5.1:二叉树中层数为i的结点至多有 2 i 2^i 2i个,其中 i ≥ 0 i \geq 0 i≥0。引理5.2:高度为k的二叉树中至多有 2 k 1 − 1 2^{k1}-1 2k1−1个结点,其中 k ≥ 0 k \geq 0 k≥0。引理5.3&…

Javaweb之javascript的小案例的详细解析

1.5.4 案例 1.5.4.1 需求说明 鲁迅说的好,光说不练假把式,光练不说傻把式。所以接下来我们需要通过案例来加强对于上述DOM知识的掌握。需求如下3个: 点亮灯泡 将所有的div标签的标签体内容后面加上:very good 使所有的复选框呈现被选中的…

CMake教程--QT项目使用CMake

CMake教程--QT项目使用CMake Chapter1 CMake教程--QT项目使用CMake1. Basic Cmake Based Project2. Executable VS Library3. Every module has its own CMakeList.txt in its folder3.1 不推荐的做法:3.2 推荐的做法 4. 强制以Debug, Release, RelWithDebInfo, Min…

【Qt之Model/View】编程

Model/View编程介绍 Qt包含一组使用模型/视图架构来管理数据和用户呈现的关系的视图类。此架构引入的功能分离使开发人员可以更灵活地自定义项的呈现方式,并提供标准的模型接口,以允许各种数据源与现有项视图一起使用。在本文档中,我们简要介…

如何确定线程栈的基址?

起 很早之前,我遇到过几个与栈相关的问题,当时总结过几篇关于线程栈的文章,分别是 《栈大小可以怎么改?》、《栈局部变量优化探究,意外发现了 vs 的一个 bug ?》、《栈又溢出了》、《有趣的异常》。在这几…

外星人笔记本键盘USB协议逆向

前言 我朋友一台 dell g16 购买时直接安装了linux系统,但是linux上没有官方的键盘控制中心,所以无法控制键盘灯光,于是我就想着能不能逆向一下键盘的协议,然后自己写一个控制键盘灯光的程序。我自己的外星人笔记本是m16&#xff…