前端线上调试指南

2,716 阅读2分钟
原文链接: zhuanlan.zhihu.com

场景

前端工程师可能会遇到如下的场景:测试环境功能都 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 一样的效果。