HTTP 代理服务器技术选型之旅

HTTP 代理服务器技术选型之旅

背景

长期以来,贴吧开发人员多,业务耦合大,需求变化频繁,因此容易产生 bug。而我所负责的广告相关业务,和 UI 密切相关,一旦因为某种原因(甚至是被别人改了代码)产生了 bug,必然大幅度影响广告收入。

解决问题的一种方法在于频繁的测试,既然避免不了代码层面的耦合,那总是可以通过定时的检查来避免问题。所以我们维护了一组核心 case,密切关注最核心的功能。选择核心 case 实际上是在覆盖面和测试成本之间的权衡,然而多个 case 有不同的测试步骤,测试效率始终难以提高。

因此,我们的目标是建立一个代理服务器,能够在运行时把任何包(包括线上包)的数据改成我希望的样子。换句话说,这个代理服务器也可以理解为一个私服,它能够获得客户端的请求数据并作出修改,也可以获得服务端的响应数据并做修改。

代理服务器工作模型

在早期版本中,我们选择了简单的 HTTP 协议。这种选择对技术的要求最低,我们自己实现了一个代理服务器,开启 socket,监听端口,然后将客户端的请求发送给服务器,再把服务器的返回数据传回客户端。这种模式也被称为:“中间人模式”(MITM: Man In The Middle)。

虽然道理很简单,但实现起来还是有些地方要注意。首先,当 socket 接受数据后,应该新开一个进程/线程 进行处理。既然涉及到新的进程/线程,就一定要注意它的释放时机,否则会导致内存无限制增加。

其次,对于 socket 来说,它并没有等待函数,也就是说我无从得知何时有数据可读,因此这个艰巨的任务就交给了 select。我们把需要监听的 socket 对象作为参数传入其中,函数会一直阻塞,直到有可读、可写的对象,或者达到超时时间。

Keep-Alive 字段可以复用 TCP 连接,是一种常见的 HTTP 协议的优化方式,在 HTTP 1.1 中已经是默认选项。填写这个字段后,Server 返回的数据可能是分批次的,这样能够改善用户体验,但也会增加代理服务器的实现难度。所以代理服务器在作为客户端,向真正服务器请求数据时,应该删除这个字段。

由于整套流程都是自己实现,因此可以比较容易的 HOOK 住上下行数据并做修改。只有注意在接收到全部数据后再做修改即,整个流程可以用下图简单表示:

代理服务器的工作模式

技术选型

短连接

由于长连接基于 TCP,不用每次新建连接,也省略了不必要的 HTTP 报文头部,效率明显优于 HTTP。所以各大公司基本上选择了长连接作为实际生产环境下的连接方式。然而由于不熟悉 WebSocket 协议,并且我们依然支持短连接,所以代理服务器最终选择了 HTTP 协议。

要想实现这一点, 就得在应用启动时,模拟后台向客户端发送一段控制信息,强制客户端选择 HTTP 请求。这样一来,即使是线上包也可以走代理服务器。

HTTPS

由于苹果强制要求使用 HTTPS,虽然已经延期,但也是明年的趋势。考虑到后续的使用,我们决定对之前实现的代理服务器进行升级。由于 HTTPS 涉及到请求协议的解析,以及加密解密和证书管理,上述自研方案很难 hold 住。经过一番调研,最后选择了一个比较知名的开源库 mitmproxy

Mitmproxy

选择这个库最主要的理由是它直接支持 HTTPS,不过没有中文文档,国内的使用相对来说比较少,所以在接入的时候可能会略花一点时间。

这是一个 python 库, 首先要安装 virtualenv,如果本地没装的话输入:

sudo pip install virtualenv
安装好了以后,进入 mitmproxy/venv3.5/bin 文件夹输入:
source ./active
这样就可以启用 virtualenv 环境了。

Hook 脚本

这个库可以理解为命令行中可交互版本的 Charles,不过我并不打算用它的这个功能。因为我的需求主要是利用脚本来 Hook 请求, 所以我选择了 mitmdump 这个工具。使用它的时候可以指定脚本:

mitmdump -s "xxx.py"

脚本也很简单,我们可以重写 requeest 或者 receive 函数:

def request(flow):
        flow.response.content = "<p>hello world</p>"

运行脚本以后,把手机的代理设为本机 ip 地址,端口号改为 8080,然后用手机浏览器打开 http://mitm.it/,如果一切配置顺利,你会看到证书的安装界面。

安装好证书后,用手机访问任何一个网站(包括 HTTPS),你应该都会看到一个小小的 hello world,至此所有的配置就完成了。

bug 修改

这个开源库有一个很严重的 bug,在解析 multipart 类型的数据时可能会发生。它使用了 splitline 方法来分割换行符,然而如果数据中有 \n 的话,就会因此丢失。很不幸的是,很多 protobuf 编码后的数据都有 \n,一旦丢失就会导致解析失败。

如果你不幸遇到了和我一样的坑,可以把相关代码改成我的版本:

for i in content.split(b"--" + boundary):
    parts = i.split(b‘\r\n\r\n‘, 2)
    if len(parts) > 1 and parts[0][0:2] != b"--":
        match = rx.search(parts[0])
        if match:
            key = match.group(1)
            value = parts[1][0:len(parts[1])-2] # Remove last \r\n
            r.append((key, value))

More

到了这一步,基本上已经成功实现支持 HTTPS 的代理服务器了。后续要处理的可能就是解析 protobuf,完善业务代码等等琐碎的事情,只要小心谨慎,基本上不会有问题。

时间: 2024-08-03 21:29:35

HTTP 代理服务器技术选型之旅的相关文章

我的“技术架构”之旅

导言:很久没写过涉及技术的文章了,因为进行职业转型后对技术有种很纠结的心态.热爱--每每看到五颜六色的代码窗口就会心里发酸,想起曾经那是生活中的一份灿烂心情:不自信--这么久离开技术会不会已经落后生疏(虽然一直没有脱离技术的学习与参与,但是失去了一线写代码的实践).今天恰好去参加AWS(亚马逊云服务)的一个区域讨论会,一位亚马逊的架构师在为大家讲解AWS云服务及一些案例的架构设计,很多熟悉的概念,还有这位架构师的谦逊和真实,一切是那么亲切.所以心血来潮,想回顾一下自己做架构的职业之旅. 本想自己

移动开发主流框架的选取以及技术选型方案解析

传统的移动开发模式主要分为三种,Native App,Web App 和 Hybrid App,对于目前微信端比较火爆的开发平台小程序,或者其他厂商推广的流应用.轻应用等开发方式,基本都离不开H5的支撑.目前App前端开发主流框架RN,Ionic,Vue都发展得不错.但是业务需求的快速发展,有些框架并不能够满足他们的需求,在不同的业务场景,受诸多约束因素的影响,研发团队应该如何在前端框架上做好选型? 根据目前51CTO社群(群号312724475)中大部分移动开发领域的开发者实际项目经验,我们邀

创业公司的技术选型

技术选型对创业公司至关重要,好的选型会让你少走弯路,产品更快推向市场,比竞争对手更快赢得客户,获得更多融资,有更多资源投入产品研发和市场扩展 … 如此往复形成良性循环.相反,每一个错误选型都会带来巨大的技术债务,我知道一些创业公司把 demo 时的选型一直用到 A 轮甚至 B 轮,然后不得不停下业务花几个月时间去重构整个系统. 可以说,对初创团队的技术 leader,最重要的事情就是选择正确的技术体系. 下面是我们技术选型的三个原则: 一.利用好创业公司技术选型的后发优势 大公司的基础设施往往超

技术选型注意事项

最近一个朋友比较烦恼,原因是他们的系统换数据库了,如果仅仅是换个数据库倒是没啥大不了,撑死了改个数据库的驱动,改改连接字符串就得了,这都是分分钟的事.但是悲哀的是表结构也得到了较大的调整,"累觉不爱"来形容这为朋友对换数据库这件事的感受再恰当不过了.而笔者对这件事有几点体会. 错误发现的越早浪费的时间越少 其实如果后面Dao实现用的是Hibernate或者是JPA那么在开发阶段换数据库就不再是什么麻烦的事情,然而他们用的是Ibatis(或者是MyBatis?忘记哪个了who care~

atitit.技术选型方法总结为什么java就是比.net有前途

#----按照不同的需要有不铜的法... 一般有开发效率,稳定性上的需要.. 作者 老哇的爪子 Attilax 艾龙,  EMAIL:[email protected] 转载请注明来源: http://blog.csdn.net/attilax #-----常规选型..一般还是java+php比较好.. 长期性:把需要都罗列出来,然后把那些在长期还用得到的标出来. 一般来说.console是最稳定性的...前端gui/web是不稳定性的...后端就是更好.. 查看历史:: 会晓得,为什么php会

技术选型--因地制宜、量体裁衣

——摘自<HTML5移动Web开发实战> c12  12.2 1.技术成熟度 一项技术是否成熟,决定了你的应用是否稳定.特别是新的技术通常意味着缺乏稳定性,在需要保证正确性和稳定性的场景(比如面向金融或者面向数量巨大的最终用户的应用),选择新技术时一定要慎重再慎重,对于一些不关键的容错性高的场景(比如内部系统),选择新技术的风险就会小很多. 2.文档 由于程序员基本都是由人类构成,因此文档好坏基本上制约着程序员的工作效率.无论你看到某项技术吹的再天花乱坠,请一定记得看看它的文档是否健全优雅,示

企业开发技术选型

http://blog.csdn.net/jwdstef/article/details/23767033 企业级开发我们在开发前需要进行技术选型,选择合适的技术,会让我们事半功倍,这就是为什么站在巨人的肩膀我们会看的更远.下面是3年前写的,过了3年出现了很多新的技术和框架,我会尽快更新出最新的技术选型,希望对大家有所帮助. 2.1. 基础架构 IOC Container: Spring, Guice 我们需要IOC Container的依赖注入作为胶水,把其他工具包粘在一起.还需要它的AOP,

JavaEE 技术选型建议,服务器配置,部署策略

基础设施环境 # 整体采用 centos6.5 + nginx + tomcat7.0 负载均衡:nginx 配置,使用 nginx 作为负载均衡,权重配置, 在web层做到水平扩展. 以及配置日志格式,支持db.cache调用次数,响应时间,做全站的监控. 支持对应参数的配置,方便日后做大数据营销的规划,对应的hive表,做分析使用 web层:采用一主一备. 建议内存16G,cpu 8 core,硬盘其它特殊要求,优化tomcat的jvm参数项. db层 :数据部署建议采用一主一备,建议内存1

基于cocos2dx的2D手游美术资源制作技术选型(2)--动作编辑器选择

Cocostudio是cocos2dx官方提供的游戏制作工具,其中包含了动作编辑器,其编辑好的动画导出的文件有三种:Atlastexture,json的AtalasTexture描述文件和plist动画描述文件,可以使用LibExtension Amature加载和播放. 但Cocostduio的动作编辑器也有一些不足的地方: 1. Cocostduio的崩溃率较高,很容易造成编辑过程中的数据丢失 2. Cocostudio的动作编辑方式对美术来说学习成本大,使用上也多不方便,美术对此非常抗拒