抱歉,您的浏览器无法访问本站

本页面需要浏览器支持(启用)JavaScript


了解详情 >

一.说明

1.说明

官方文档:https://github.com/alibaba/anyproxy/blob/master/docs/cn/src_doc.md

AnyProxy 是阿里巴巴基于 Node.js 开发的一款开源代理服务器,代理是什么大家都懂,而除代理之外,由于支持自定义rules,可修改request和resposne,因此在很多场景下如mock数据,模拟接口慢查,阻止304,调试时后端不支持跨域头Access-Control-Allow-*的时候都非常有用。(本篇着重介绍下代理和mock功能)

image.png

2.特性

优点:

  • 支持修改request和response
  • 支持注入js
  • 支持中间人代理,具备web界面过滤请求,抓包,数据支持保存事后分析
  • 开放式api可二次开发

缺点:

  • 许久未更新
  • 文档或案例难找
  • 基于node的代理性能略差

3.安装

1).安装node

安装node https://nodejs.org/en/download/ 找对应系统安装

安装后打开cmd或者终端,输入node -v

image.png

再试试npm

image.png

出现以上表示安装成功

2).安装anyproxy

全局安装

1
npm install -g anyproxy

3).启动

输入anyproxy

image.png

可以看到web界面监听在8002端口,http服务代理在8001端口,可以打开127.0.0.1:8002看一下web界面。

image.png

4.常用指令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
启动(默认代理监听8001端口,web服务在8002端口,默认不解析https端口)
anyproxy

指定代理端口
anyproxy --port 8001 (或者anyproxy -p 8001)

指定web服务端口
anyproxy --web 8002 (或者anyproxy -w 8002)

解析https端口
anyproxy --intercept (或者anyproxy -i)

指定规则文件
anyproxy --rule rules.js (或者anyproxy -r rules.js)

终端窗口不打印信息
anyproxy --silent (或者anyproxy -s)

删除所有anyproxy证书和临时文件
anyproxy --clear (或者anyproxy -c)

忽略ssl错误
anyproxy --ignore-unauthorized-ssl

指定响应速度
anyproxy --throttle 100(或者anyproxy -t 100, 单位kb/s)

监听websocket(wss)
anyproxy --ws-intercept

生成ca证书
anyproxy-ca

**
**

5.外部api

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//模块介绍,摘要
summary

//请求发送前进行拦截处理
*beforeSendRequest(requestDetail) {}

//响应发送前进行拦截处理
*beforeSendResponse(requestDetail, responseDetail) {}

//是否处理https请求
*beforeDealHttpsRequest(requestDetail) {}

//请求出错的事件拦截处理
*onError(requestDetail, error) {}

//https连接出错拦截处理
*onConnectError(requestDetail, error) {}

**
**

二.代理功能

1.PC

说代理,少不了https,一步到位吧,先生成https证书。

1
anyproxy-ca

然后会在当前目录的 .anyproxy/certificates/rootCA.crt下生成证书,是一个隐藏目录。

如我的电脑在/Users/ryan执行的anyproxy-ca,生成了/Users/ryan/.anyproxy/certificates/rootCA.crt证书。

双击去安装。

image.png

启动并监听https

1
anyproxy -i

image.png

修改网络配置,设置代理为本机的8001端口。(这步不细说了,都是老司机了)

先访问127.0.0.1:8002,再访问百度随便搜索个啥。

image.png

image.png

简单过滤下,可以看到访问百度搜索的接口是https协议,可以看到请求参数和返回值。

2.移动端

移动端的也比较简单,在统一局域网下手机代理设置为电脑ip的8001端口即可。

如需https,先在电脑上打开127.0.0.1:8002页面,可以看到左侧菜单栏有个RootCA,点击他。

(不要直接扫语雀这里的,自己电脑上要生成自己的然后手机上安装对应的证书)

image.png

后面就不用我多说了吧?跟fidder或charles一样安装证书就好了,关于ios11或者安卓7及以上版本抓包的方法请参考 https://xcz.yuque.com/shswyy/autotest/xlfh4s

3.过滤

页面上很显眼的标识了filter–过滤。

image.png

一条规则写一行,如果是多行,每一行将作为独立的过滤规则,结果集取的是过滤规则的并集,所有的过滤都将先从URL开始。

三.mock(推荐)

为什么要mock?

mock的重要性就不提了,其实charles也具备mock功能,甚至你随便用一个能提供web服务的框架不管是java也好,python也好,都可以当作mock服务器,但操作上来说还是繁琐了些。

如果是很多人长期使用的情况下,那作为一项公共服务,不断去开发维护还说得过去,否则就有点本末倒置。

对我来说,业务上要用到mock的场景不多,但真有什么问题,也比较麻烦,比如依赖的第三方查询接口,测试环境一般不稳定,挂了后面的流程我就没法走下去。

又例如列表想看多数据的分页加载情况,造数据麻烦且有污染,使用mock比较好。

如何mock?实例

常用指令中说了,有一项是-r,可以指定规则文件,需要使用rules文件来进行mock数据的返回。

mock之前,这里业务中解析为例,解析出错,无法匹配,无法进行下一步。

image-20210510163342481

首先看下接口和正常情况下的返回:

接口: http://example.com/api/detail?code=AAAAAAAAAAAAAAAAAA

返回:

1
{"code":200,"data":{"省略...."},"message":"SUCCESS"}

接口: http://example.com/list?a=b&c=d

返回:

1
{"code":200,"data":[{"省略..."},{"省略..."}],"message":"SUCCESS"}

接口:http://example.com/detail?a=xx

1
{"code":200,"data":[{"省略..."},{"省略..."}],"message":"SUCCESS"}

编写rule.js,先试试第一个接口。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
module.exports = {
*beforeSendRequest(requestDetail) {
const response1 = {
statusCode: 200,
header: { 'Content-Type': 'application/json' },
body: '省略'
};
if (requestDetail.url.indexOf('http://example.com/api/detail?code=AAAAAAAAAAAAAAAAAA') === 0) {
return {
response: response1
};
}
},
};

启动

1
anyproxy -i -r rule.js

先用curl试一下

image-20210510165225932

拿到的是规则里写的值。

发现页面上无法解析结果,实际已经走到规则里去里。猜测可能是response有问题,找下其他可用环境的返回response。

image-20210510165421453

发现response headers里东西还挺多,经过尝试,我们需要在返回值的headers里加入Access-Control-Allow-Credentials和Access-Control-Allow-Origin。

修改header内容为

1
2
3
4
5
{
'Content-Type': 'application/json;charset=UTF-8',
'Access-Control-Allow-Credentials': 'true',
'Access-Control-Allow-Origin': '填写hostname'
};

再从页面上解析下vin码,nice。

image-20210510165551996

完整rules.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
module.exports = {
*beforeSendRequest(requestDetail) {
const originHeader = {
'Content-Type': 'application/json;charset=UTF-8',
'Access-Control-Allow-Credentials': 'true',
'Access-Control-Allow-Origin': '填写hostname'
};

const response1 = {
statusCode: 200,
header: originHeader,
body: '省略'
};


if (requestDetail.url.indexOf('请求地址') === 0) {
return {
response: response1
};
};
};

beforeSendRequest和beforeSendResponse

在说明的图示中可以看到有beforeSendRequest和beforeSendResponse两个方法。字面上意思也很好理解,请求发送前和返回值发送前嘛。其作用分别:

beforeSendRequest:请求发送前,可更改请求(包括参数啊,header啊,地址等),或者直接返回自定义内容给你。

beforeSendResponse:请求发送后将返回值传给发送方之前,可修改response的主体内容,修改返回值的header,状态码,或者直接覆盖response。

PS: 上述的mock例子里,因为明知道这几个接口是挂的,也就无需实际发送请求,那么直接用beforeSendRequest方法返回我自定义的返回值即可。

关于修改request和response的官方的几个例子: https://github.com/alibaba/anyproxy/tree/master/rule_sample

四.更多实例

1).替换请求地址

例如你有多个环境,将a环境的请求 发送给 b环境,再返回给页面

原本只有8条数据

image.png

现在有2282条了…

image.png

1
2
3
4
5
6
7
8
9
10
11
12
module.exports = {
*beforeSendRequest(requestDetail) {
if (requestDetail.url.search('原始请求url') != -1) {
const newRequestOptions = requestDetail.requestOptions;
newRequestOptions.headers.Cookie = ''
newRequestOptions.hostname = '真实请求地址的hostname';
newRequestOptions.headers.Host = '真实请求地址的host';
console.log(requestDetail);
return requestDetail;
}
},
};

requestDetail.requestOptions的其他属性:

protocol: 协议,如http, https

hostname:域名

port:端口

path:路径

method:请求方法

2).模拟延迟

例如延迟10秒再返回

1
2
3
4
5
6
7
8
9
10
11
module.exports = {
*beforeSendResponse(requestDetail, responseDetail) {
if (requestDetail.url.indexOf('请求地址')===0) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve({ response: responseDetail.response });
}, 10000); //单位是毫秒
});
}
},
};

3).接口请求失败返回自定义response

有时候不想直接返回自定义,想先去请求原始地址,如果报错了,在用自定义返回值。

为了方便,我直接写一个不存在的地址

image-20210510164617621

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
module.exports = {
*beforeSendResponse(requestDetail, responseDetail) {
const originHeader = {
'Content-Type': 'application/json;charset=UTF-8',
'Access-Control-Allow-Credentials': 'true',
'Access-Control-Allow-Origin': '请求地址https//+host'
};

const response1 = {
statusCode: 200,
header: originHeader,
body: '{"code":200,"data":{"省略..."},"message":"SUCCESS"}'
};
if (requestDetail.url.indexOf('原始请求url') === 0) {
const newResponse = responseDetail.response;
if(newResponse.statusCode != 200){
return {response: response1}
};
return responseDetail.response
}
}
};

评论