场景
前端工程师可能会遇到如下的场景:测试环境功能都 ok ,到了生产环境就出问题,改完 bug 上线后发现又引入了新的问题。只能再次重复这个过程。
所以能不能不上线,将本地代码直接作用于线上,来调试功能呢。
我们有如下工具可以选择 fiddler (windows), charles (mac), mitmproxy (可自定义脚本)
下面我们举 charles 和 mitmproxy 为例子说明
charles
1. 打开 charles, 点击 Tools -> Map Local -> Add, 将需要的 Path 映射到 Local path (自己的本地目录),然后找到自己需要映射的目录或文件,(比如 js 目录)。
2. 这里面我们也可以选择 Map Remote 模式,它能映射到 url 地址,如 www.example.com/js -> test.example.com/js
3. 接下来我们只需让浏览器代理到 charles 即可,charles 默认开启的是 http 代理,8888 端
- Chrome 用户下载插件 switchyOmega,配置如下
- Safari 用户不用装插件,只需 charles -> Proxy -> MacosProxy 选中即可。
4. 配置完成!接下来你本地对 js 的改动,直接能够作用在 exampel.com 上。
mitmproxy
mitmproxy 没有界面,只能在终端运行,不过它可以定制 python 插件,实现想要的功能。
接下来我先介绍下原理,为什么本地的文件能直接作用于线上。
原理在于我们使用了代理,或者更准确一点叫中间人劫持,不过这个中间人是我们自己。
代理软件在代理我们访问的网页时,会根据我们配置的规则修改返回给我们的内容,比如我们访问 example.com/js/a.js 的时候,发现我们配置了规则是去本地找 a.js 这个文件,找到这个文件,拿到内容后,会直接将 response 的 boby 内容改成本地的内容,这样浏览器就会根据本地内容做渲染。
我们用 mitmproxy 的脚本来实现,自定义一个文件 test.py
import re
import glob
from mitmproxy import http
# 拿到本地 a.js 的内容
main_js = glob.glob('./js/a\.js')
main_content = ''
if main_js:
with open(main_js[0]) as f:
main_content = f.read()
# 匹配 example.com/js/a.js 的内容
pattern = re.compile("http://example\.com/js/a\.js")
def request(flow: http.HTTPFlow) -> None:
if pattern.match(flow.request.pretty_url):
flow.response = http.HTTPResponse.make(
200,
main_content,
{"Content-Type": "application/javascript",
"Content-Encoding": "gzip"}
)
然后运行 mitmdump -s test.py 就可达到和 charles 一样的效果。