无意中发现了一个巨牛的人工智能教程,忍不住分享一下给大家。教程不仅是零基础,通俗易懂,而且非常风趣幽默,像看小说一样!觉得太牛了,所以分享给大家。点这里可以跳转到教程。

文章目录

  • 与普通代理的区别
  • 实现方式
    • 接收请求
    • 代理请求
    • 插件机制
  • 应用场景
  • 后期功能增强

说到代理,大多数情况我们都会想到通过浏览器设置的正向代理,以及类似nginx的反向代理;而实际上除此之外还有一种基于host方式实现的代理。

本文主要讲述,如何实现一个基于host方式的http代理,以及它与普通代理之间的区别。这种方式的代理主要可以应用于哪些实际的测试场景。

与普通代理的区别

所谓的普通代理,就是我们日常会用到的那种代理,通常需要客户端本身支持,使用时对客户端进行代理信息配置。最常见的就是对浏览器、curl等客户端配置代理,一般主要用来翻墙的!

而host代理则不是主流的代理方式,它的特点是通过设置host就能实现代理,而不需客户端本身支持,相对应用的访问更广一些。下面我们就来逐一对比下它们的具体区别:

对比项 普通代理 HOST代理
需要客户端支持
设置方式 配置客户端 配置HOST
支持透明代理
支持绝对路径
支持非80端口
实现方式 socket http
URL路径支持 绝对路径 相对路径
代理服务与客户端同机 支持 不支持
代理配置方式 域名配置灵活 host配置不灵活

通过对比可以发现它们都能满足基本的HTTP代理功能,主要区别在于适用的场景有所不同;普通代理只要客户端本身支持基本上什么请求都可以代理,HOST代理只要请求是80/443端口都可以代理。

实现方式

接收请求

实现一个HOST代理是非常简单的,你只需要基于一个现成的WEB框架,比如:Flask,Tornado;再加上一个url请求框架即可,比如:requests。而首先你得实现一个可以接手任意URL路径的请求处理函数,如下:

from werkzeug.routing import BaseConverter
from flask import Flask, request, jsonifyclass RegexConverter(BaseConverter):def __init__(self, url_map, *args):super(RegexConverter, self).__init__(url_map)self.url = url_mapself.regex = args[0]   # 正则的匹配规则def to_python(self, value):return valueapp = Flask(__name__, static_url_path='/do_not_use_this_path__')
app.url_map.converters['re'] = RegexConverter@app.route('/<re(r".*"):path>')
def proxy(path):url = request.base_urlquery = request.argsmethod = request.methodheaders = request.headersform_data = request.formbody = request.datafiles = request.filespayload = {'path': f'/{path}','url': url,'method': method,'headers': dict(headers),'query': query,'form_data': form_data,'body': body.decode('utf-8'),'files': files}return jsonify(payload)if __name__ == '__main__':app.run(host='0.0.0.0', port=80)

启动这个web服务之后,只要在host文件中配置一个指向该服务所在机器的IP和目标域名映射即可。比如:

# host文件添加一个映射
10.0.0.1 www.baidu.com

之后,就可以在浏览器访问http://www.baidu.com这个网址了,路径内容和参数随便输,它都会完整把你请求的信息给返回来,类似一个镜像服务。效果如下:

代理请求

目前来说,我们已经完成HTTP代理的一半功能了,剩下的就是如何去发送获取到的HTTP请求,之后在把请求响应内容组装好,再发回给浏览器或客户端。首先是组装要发送的请求,样例代码如下:

class METHOD:GET = 'GET'POST = 'POST'PUT = 'PUT'DELETE = 'DELETE'HEAD = 'HEAD'OPTIONS = 'OPTIONS'def warp_request_data(payload):""":param payload: {'path': path,'url': url,'method': method,'headers': dict(headers),'query': query,'form_data': form_data,'body': body.decode('utf-8'),'files': files}:return:"""send_data = {'method': payload['method'], 'url': payload['url'],'headers': payload['headers'], 'data': None, 'files': None}if payload['method'] in (METHOD.GET, METHOD.HEAD, METHOD.OPTIONS):send_data['data'] = payload['query']elif payload['method'] in (METHOD.POST, METHOD.DELETE, METHOD.PUT):if payload['query']:payload['url'] = f"{payload['url']}?{urllib.parse.urlencode(payload['query'])}"if payload['form_data']:ct = payload['headers'].get('Content-Type')if 'application/x-www-form-urlencoded' in ct:send_data['data'] = payload['form_data']elif 'multipart/form-data' in ct:send_data['data'] = payload['form_data']send_data['files'] = payload['files']elif payload['body']:send_data['data'] = payload['body']elif payload['files']:send_data['files'] = payload['files']return send_data

接着,通过requests发送组装好的请求数据内容。方法如下:

from requests import request as senderdef send_request(req):return sender(req['method'].lower(), req['url'], headers=req['headers'],data=req['data'], files=req['files'])

最后,把获取到的响应进行再次组装,便于主程序直接返回内容给浏览器或客户端。代码如下:

def warp_response_data(rep):body = rep.contentif 'Transfer-Encoding' in rep.headers:      # 不支持chunkdel rep.headers['Transfer-Encoding']rep.headers['Content-Length'] = len(body)if 'Connection' in rep.headers:             # 不支持keep-alivedel rep.headers['Connection']if 'Content-Encoding' in rep.headers:       # 不支持gzipdel rep.headers['Content-Encoding']rep.headers['Server'] = 'host proxy/0.1'    # 修改服务器信息return {'code': rep.status_code,'headers': dict(rep.headers),'body': body}

同时,需要在http处理的主函数中添加对http请求的代理操作。最后的http处理主函数新增内容如下:

@app.route('/<re(r".*"):path>')
def proxy(path):req = Action.warp_request_data(payload)rep = Action.send_request(req)ret = Action.warp_response_data(rep)return ret['body'], ret['code'], ret['headers']

插件机制

目前为止完成了这么多功能之后,一个http的代理就已经初步完成了。只是目前仅仅是做了代理,但是没有任何的作用。因为我们不能对它进行任何操作。要让它变得有意义就得添加插件机制,让用户可以对代理的请求进行处理和操作。

首先,定义一个插件类,用于注册和执行插件内容。代码如下:

class Plugins:def fire(self, context):        # 插件事件触发for func in self.events:func(context)def register(self, func):       # 插件事件注册self.events.append(func)class PRE_PROXY(Plugins):def __init__(self):self.events = []class POST_PROXY(Plugins):def __init__(self):self.events = []pre_proxy = PRE_PROXY()
post_proxy = POST_PROXY()def before_proxy(func):         # 注册触发代理前装饰器pre_proxy.register(func)return funcdef after_proxy(func):          # 注册触发代理后装饰器post_proxy.register(func)return func

同时,也要在http主函数中添加插件函数的调用,修改后的代码如下:

...context = {}req = Action.warp_request_data(payload)context['request'] = reqpre_proxy.fire(context)         # 触发代理前事件rep = Action.send_request(req)ret = Action.warp_response_data(rep)context['response'] = retpost_proxy.fire(context)        # 触发代理后事件
...

最后,在同目录下新建一个插件脚本文件script.py。其内容如下:

from .plugins import before_proxy, after_proxy@before_proxy
def before(context):print(context)@after_proxy
def after(context):print(context)

这个脚本内容非常的简单,导入2个注册装饰器分别用来注册代理前和代理后的事件。注册函数可以接收到一个请求和响应的上下文对象参数,这里仅仅是打印了出来。

当然,插件还可以做很多其它的事情,比如:过滤特定url并保存请求信息;修改请求和响应信息内容等。完整项目代码请关注公众号并回复hproxy即可!

应用场景

这类http代理主要应用的场景一般多为测试或者开发,日常生活中翻墙还是要是普通代理。主要可以用于辅助测试,比如:mock系统,api接口测试等。

对于mock系统,可以用来录制mock内容,尤其是针对服务端请求第三方接口的请求录制。比如:

  • 录制调用第三方银行的接口请求,作为mock内容
  • 选择性的mock同域名下的部分URL请求,其它URL则透传

用于api自动化测试,可以直接录制对应接口的API请求,用于快速生成自动化测试用例。当然还可以用于安全测试,篡改指定的http请求内容。

后期功能增强

虽然目前该demo程序已经可以开始用于辅助测试工作了,但是想要更加的易用,还有很多的特性需要支持。

  • 协程支持
  • 过滤功能
  • https支持
  • websocket支持
  • keep-alive支持
  • chunk支持

获取更多关于Python和测试开发相关的文章,请扫描如下二维码!

基于host的http代理--hproxy相关推荐

  1. python如何基于redis实现ip代理池

    这篇文章主要介绍了python如何基于redis实现ip代理池,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 使用apscheduler库定时爬取i ...

  2. 基于子类的动态代理:

    基于子类的动态代理: 提供者:第三方的CGLib,如果报asmxxxx异常,需要导入asm.jar. <dependency> <groupId>cglib</group ...

  3. oracle ebs 基于host(主机文件)并发程序的开发,Oracle EBS 基于Host(主机文件)并发程序的开发...

    您可以将程序命名为 .prog,其中 是在"可执行并发程序"窗口的"执行文件"字段中输入的值.然后,使用执行文件名(无扩展名)创建与 fndcpesr 的符号链 ...

  4. Spring框架----基于子类的动态代理

    上节,我们提到了基于接口的动态代理. 基于接口的动态代理 来完成通过中间代理商,消费者从生产商那里购买产品的功能. 这种动态代理要求第三方jar包的支持. cglib依赖,版本是2.1_3 基于子类的 ...

  5. Spring框架----基于接口的动态代理

    由我们前面对代理的分析 对代理的分析 有生产商,销售人员和消费者这3个角色,销售人员是中间代理商.代理销售和售后的工作. 而在刚开始的时候,我们并没有销售人员.根据这样的思路,我们写出以下代码 接口I ...

  6. 基于子类的动态代理(使用CBl工具)

    基于子类的动态代理 要求:                  1.被代理类不能是最终类,不能被finaly修饰                     提供者:第三方 CGlib           ...

  7. ProxyPool proxy-pool: java 基于springboot框架获取代理ip

    PROXY-POOL: java 基于springboot框架获取代理ip

  8. 第六篇 - 手写基于接口实现动态代理

    Github源码下载地址:https://github.com/chenxingxing6/sourcecode/tree/master/code-proxy 一.前言 我们知道常见的动态代理有两种实 ...

  9. 基于R语言的代理模型(高斯过程、贝叶斯优化、敏感性分析、异方差性等)高级技术应用

    基于R语言的代理模型(高斯过程.贝叶斯优化.敏感性分析.异方差性等)高级技术应用 直播时间:10月30日-10月31日.11月6日-7日(4天+1周辅导练习) (上午9:30-12:00  下午14: ...

  10. 基于fiddler插件的代理扫描系统:越权漏洞检测

    基于fiddler插件的代理扫描系统:越权漏洞检测 # 概述 ##越权检测原理 ###系统架构 #基本步骤 待优化与工具联动 工具联动: 其他漏洞检测 # 概述 随着现在企业安全水平的提高, 单独依赖 ...

最新文章

  1. transforms.compose()
  2. Atitit.java相比c#.net的优点 优缺点  v2 q330
  3. avue 文字点击 弹窗_经验 | UI设计师必懂的App弹窗设计方法
  4. 2013年1月31号
  5. GPU Gems1 - 22 颜色控制(Color Controls)
  6. Servelt中的ServletContext对象
  7. 单片机与PC机一样都是计算机,51单片机与PC机通信资料
  8. 第一课[编辑器设置-VC++6.0]
  9. H5实例 移动端页面练习
  10. 对复杂字典DictionaryT1,T2排序问题
  11. Atitit ABI FFI 的区别与联系 attilax总结
  12. 从Android support到Androidx
  13. python字典快速一览
  14. android基础--PreferenceActivity
  15. 信必优成功案例 – 中国网络电视台(CNTV)
  16. 聚石塔,云鼎,多多云-----有一种坑叫盲打
  17. 以Skyline问题来看hard问题在面试的时候如何解决?
  18. 基层教学组织评估系统6_项目完结心得收获、思考人生篇
  19. 按“Win+E”键出现【找不到应用程序】或【explore.exe找不到】的解决方法
  20. P1039 [NOIP2003 提高组] 侦探推理

热门文章

  1. 个人总结 - JS逆向解析
  2. 诚之和:太平鸟难渡“抄袭劫”?
  3. php path_info orig_path_info
  4. 华中师范大学计算机学院学分绩,华中师范大学全日制本科交换生学分转换、成绩认定管理办法...
  5. Nuvoton M0518 之 Slave SPI通信注意事项
  6. 【LeetCode】马三来刷题之 Single Number
  7. 一文教你玩转Mybatis,超详细代码讲解与实战
  8. Android应用源码基于安卓的个人隐私监控项目
  9. 任正非带领华为三分天下的7大杀招
  10. 用来打发时间的EUserv