mirror of
https://github.com/alibaba/anyproxy.git
synced 2025-04-21 19:04:23 +00:00
1668 lines
75 KiB
HTML
1668 lines
75 KiB
HTML
|
|
<!DOCTYPE HTML>
|
|
<html lang="cn" >
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
|
|
<title>简介 · AnyProxy</title>
|
|
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
|
<meta name="description" content="">
|
|
<meta name="generator" content="GitBook 3.2.2">
|
|
<meta name="author" content="AnyProxy">
|
|
|
|
|
|
|
|
<link rel="stylesheet" href="../gitbook/style.css">
|
|
|
|
|
|
|
|
|
|
<link rel="stylesheet" href="../gitbook/gitbook-plugin-highlight/website.css">
|
|
|
|
|
|
|
|
<link rel="stylesheet" href="../gitbook/gitbook-plugin-search/search.css">
|
|
|
|
|
|
|
|
<link rel="stylesheet" href="../gitbook/gitbook-plugin-fontsettings/website.css">
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<meta name="HandheldFriendly" content="true"/>
|
|
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
|
|
<meta name="apple-mobile-web-app-capable" content="yes">
|
|
<meta name="apple-mobile-web-app-status-bar-style" content="black">
|
|
<link rel="apple-touch-icon-precomposed" sizes="152x152" href="../gitbook/images/apple-touch-icon-precomposed-152.png">
|
|
<link rel="shortcut icon" href="../gitbook/images/favicon.ico" type="image/x-icon">
|
|
|
|
|
|
<link rel="next" href="./" />
|
|
|
|
|
|
|
|
<link rel="shortcut icon" href="/assets/favicon.png" type="image/png">
|
|
<link rel="stylesheet" href="/assets/website.css">
|
|
<script src="/assets/main.js" ></script>
|
|
</head>
|
|
<body>
|
|
<div>
|
|
|
|
</div>
|
|
|
|
<div class="book">
|
|
<div class="book-summary">
|
|
|
|
|
|
<div id="book-search-input" role="search">
|
|
<input type="text" placeholder="Type to search" />
|
|
</div>
|
|
|
|
|
|
<nav role="navigation">
|
|
|
|
|
|
|
|
<ul class="summary">
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="chapter active" data-level="1.1" data-path="./">
|
|
|
|
<a href="./">
|
|
|
|
|
|
<div class="summary-title-span 简介">
|
|
简介
|
|
</div>
|
|
|
|
|
|
</a>
|
|
|
|
|
|
|
|
</li>
|
|
|
|
<li class="chapter " data-level="1.2" data-path="./">
|
|
|
|
<a href="./#快速开始">
|
|
|
|
|
|
<div class="summary-title-span 快速开始">
|
|
快速开始
|
|
</div>
|
|
|
|
|
|
</a>
|
|
|
|
|
|
|
|
<ul class="articles">
|
|
|
|
|
|
<li class="chapter " data-level="1.2.1" data-path="./">
|
|
|
|
<a href="./#安装">
|
|
|
|
|
|
<div class="summary-title-span 安装">
|
|
安装
|
|
</div>
|
|
|
|
|
|
</a>
|
|
|
|
|
|
|
|
</li>
|
|
|
|
<li class="chapter " data-level="1.2.2" data-path="./">
|
|
|
|
<a href="./#启动">
|
|
|
|
|
|
<div class="summary-title-span 启动">
|
|
启动
|
|
</div>
|
|
|
|
|
|
</a>
|
|
|
|
|
|
|
|
</li>
|
|
|
|
<li class="chapter " data-level="1.2.3" data-path="./">
|
|
|
|
<a href="./#其他命令">
|
|
|
|
|
|
<div class="summary-title-span 其他命令">
|
|
其他命令
|
|
</div>
|
|
|
|
|
|
</a>
|
|
|
|
|
|
|
|
</li>
|
|
|
|
<li class="chapter " data-level="1.2.4" data-path="./">
|
|
|
|
<a href="./#作为npm模块使用">
|
|
|
|
|
|
<div class="summary-title-span 作为npm模块启动">
|
|
作为npm模块启动
|
|
</div>
|
|
|
|
|
|
</a>
|
|
|
|
|
|
|
|
</li>
|
|
|
|
|
|
</ul>
|
|
|
|
</li>
|
|
|
|
<li class="chapter " data-level="1.3" data-path="./">
|
|
|
|
<a href="./#代理https">
|
|
|
|
|
|
<div class="summary-title-span 代理HTTPS">
|
|
代理HTTPS
|
|
</div>
|
|
|
|
|
|
</a>
|
|
|
|
|
|
|
|
</li>
|
|
|
|
<li class="chapter " data-level="1.4" data-path="./">
|
|
|
|
<a href="./#rule模块">
|
|
|
|
|
|
<div class="summary-title-span rule模块">
|
|
rule模块
|
|
</div>
|
|
|
|
|
|
</a>
|
|
|
|
|
|
|
|
<ul class="articles">
|
|
|
|
|
|
<li class="chapter " data-level="1.4.1" data-path="./">
|
|
|
|
<a href="./#开发示例">
|
|
|
|
|
|
<div class="summary-title-span 开发示例">
|
|
开发示例
|
|
</div>
|
|
|
|
|
|
</a>
|
|
|
|
|
|
|
|
</li>
|
|
|
|
<li class="chapter " data-level="1.4.2" data-path="./">
|
|
|
|
<a href="./#处理流程">
|
|
|
|
|
|
<div class="summary-title-span 处理流程">
|
|
处理流程
|
|
</div>
|
|
|
|
|
|
</a>
|
|
|
|
|
|
|
|
</li>
|
|
|
|
<li class="chapter " data-level="1.4.3" data-path="./">
|
|
|
|
<a href="./#如何引用">
|
|
|
|
|
|
<div class="summary-title-span 如何引用">
|
|
如何引用
|
|
</div>
|
|
|
|
|
|
</a>
|
|
|
|
|
|
|
|
</li>
|
|
|
|
|
|
</ul>
|
|
|
|
</li>
|
|
|
|
<li class="chapter " data-level="1.5" data-path="./">
|
|
|
|
<a href="./#rule接口文档">
|
|
|
|
|
|
<div class="summary-title-span rule接口文档">
|
|
rule接口文档
|
|
</div>
|
|
|
|
|
|
</a>
|
|
|
|
|
|
|
|
<ul class="articles">
|
|
|
|
|
|
<li class="chapter " data-level="1.5.1" data-path="./">
|
|
|
|
<a href="./#summary">
|
|
|
|
|
|
<div class="summary-title-span rule-title">
|
|
summary
|
|
</div>
|
|
|
|
|
|
</a>
|
|
|
|
|
|
|
|
</li>
|
|
|
|
<li class="chapter " data-level="1.5.2" data-path="./">
|
|
|
|
<a href="./#beforesendrequest">
|
|
|
|
|
|
<div class="summary-title-span rule-title">
|
|
beforeSendRequest
|
|
</div>
|
|
|
|
|
|
</a>
|
|
|
|
|
|
|
|
</li>
|
|
|
|
<li class="chapter " data-level="1.5.3" data-path="./">
|
|
|
|
<a href="./#beforesendresponse">
|
|
|
|
|
|
<div class="summary-title-span rule-title">
|
|
beforeSendResponse
|
|
</div>
|
|
|
|
|
|
</a>
|
|
|
|
|
|
|
|
</li>
|
|
|
|
<li class="chapter " data-level="1.5.4" data-path="./">
|
|
|
|
<a href="./#beforedealhttpsrequest">
|
|
|
|
|
|
<div class="summary-title-span rule-title">
|
|
beforeDealHttpsRequest
|
|
</div>
|
|
|
|
|
|
</a>
|
|
|
|
|
|
|
|
</li>
|
|
|
|
<li class="chapter " data-level="1.5.5" data-path="./">
|
|
|
|
<a href="./#onerror">
|
|
|
|
|
|
<div class="summary-title-span rule-title">
|
|
onError
|
|
</div>
|
|
|
|
|
|
</a>
|
|
|
|
|
|
|
|
</li>
|
|
|
|
<li class="chapter " data-level="1.5.6" data-path="./">
|
|
|
|
<a href="./#onconnecterror">
|
|
|
|
|
|
<div class="summary-title-span rule-title">
|
|
onConnectError
|
|
</div>
|
|
|
|
|
|
</a>
|
|
|
|
|
|
|
|
</li>
|
|
|
|
|
|
</ul>
|
|
|
|
</li>
|
|
|
|
<li class="chapter " data-level="1.6" data-path="./">
|
|
|
|
<a href="./#rule样例">
|
|
|
|
|
|
<div class="summary-title-span rule样例">
|
|
rule样例
|
|
</div>
|
|
|
|
|
|
</a>
|
|
|
|
|
|
|
|
<ul class="articles">
|
|
|
|
|
|
<li class="chapter " data-level="1.6.1" data-path="./">
|
|
|
|
<a href="./#使用本地数据">
|
|
|
|
|
|
<div class="summary-title-span sample-title">
|
|
使用本地数据
|
|
</div>
|
|
|
|
|
|
</a>
|
|
|
|
|
|
|
|
</li>
|
|
|
|
<li class="chapter " data-level="1.6.2" data-path="./">
|
|
|
|
<a href="./#修改请求头">
|
|
|
|
|
|
<div class="summary-title-span sample-title">
|
|
修改请求头
|
|
</div>
|
|
|
|
|
|
</a>
|
|
|
|
|
|
|
|
</li>
|
|
|
|
<li class="chapter " data-level="1.6.3" data-path="./">
|
|
|
|
<a href="./#修改请求数据">
|
|
|
|
|
|
<div class="summary-title-span sample-title">
|
|
修改请求数据
|
|
</div>
|
|
|
|
|
|
</a>
|
|
|
|
|
|
|
|
</li>
|
|
|
|
<li class="chapter " data-level="1.6.4" data-path="./">
|
|
|
|
<a href="./#修改请求的目标地址">
|
|
|
|
|
|
<div class="summary-title-span sample-title">
|
|
修改请求的目标地址
|
|
</div>
|
|
|
|
|
|
</a>
|
|
|
|
|
|
|
|
</li>
|
|
|
|
<li class="chapter " data-level="1.6.5" data-path="./">
|
|
|
|
<a href="./#修改请求协议">
|
|
|
|
|
|
<div class="summary-title-span sample-title">
|
|
修改请求协议
|
|
</div>
|
|
|
|
|
|
</a>
|
|
|
|
|
|
|
|
</li>
|
|
|
|
<li class="chapter " data-level="1.6.6" data-path="./">
|
|
|
|
<a href="./#修改返回状态码">
|
|
|
|
|
|
<div class="summary-title-span sample-title">
|
|
修改返回状态码
|
|
</div>
|
|
|
|
|
|
</a>
|
|
|
|
|
|
|
|
</li>
|
|
|
|
<li class="chapter " data-level="1.6.7" data-path="./">
|
|
|
|
<a href="./#修改返回头">
|
|
|
|
|
|
<div class="summary-title-span sample-title">
|
|
修改返回头
|
|
</div>
|
|
|
|
|
|
</a>
|
|
|
|
|
|
|
|
</li>
|
|
|
|
<li class="chapter " data-level="1.6.8" data-path="./">
|
|
|
|
<a href="./#修改返回内容并延迟">
|
|
|
|
|
|
<div class="summary-title-span sample-title">
|
|
修改返回内容并延迟
|
|
</div>
|
|
|
|
|
|
</a>
|
|
|
|
|
|
|
|
</li>
|
|
|
|
|
|
</ul>
|
|
|
|
</li>
|
|
|
|
<li class="chapter " data-level="1.7" data-path="./">
|
|
|
|
<a href="./#证书配置">
|
|
|
|
|
|
<div class="summary-title-span 证书配置">
|
|
证书配置
|
|
</div>
|
|
|
|
|
|
</a>
|
|
|
|
|
|
|
|
<ul class="articles">
|
|
|
|
|
|
<li class="chapter " data-level="1.7.1" data-path="./">
|
|
|
|
<a href="./#osx系统信任ca证书">
|
|
|
|
|
|
<div class="summary-title-span OSX系统信任CA证书">
|
|
OSX系统信任CA证书
|
|
</div>
|
|
|
|
|
|
</a>
|
|
|
|
|
|
|
|
</li>
|
|
|
|
<li class="chapter " data-level="1.7.2" data-path="./">
|
|
|
|
<a href="./#windows系统信任ca证书">
|
|
|
|
|
|
<div class="summary-title-span Windows系统信任CA证书">
|
|
Windows系统信任CA证书
|
|
</div>
|
|
|
|
|
|
</a>
|
|
|
|
|
|
|
|
</li>
|
|
|
|
<li class="chapter " data-level="1.7.3" data-path="./">
|
|
|
|
<a href="./#配置osx系统代理">
|
|
|
|
|
|
<div class="summary-title-span 配置OSX系统代理">
|
|
配置OSX系统代理
|
|
</div>
|
|
|
|
|
|
</a>
|
|
|
|
|
|
|
|
</li>
|
|
|
|
<li class="chapter " data-level="1.7.4" data-path="./">
|
|
|
|
<a href="./#配置浏览器http代理">
|
|
|
|
|
|
<div class="summary-title-span 配置浏览器HTTP代理">
|
|
配置浏览器HTTP代理
|
|
</div>
|
|
|
|
|
|
</a>
|
|
|
|
|
|
|
|
</li>
|
|
|
|
<li class="chapter " data-level="1.7.5" data-path="./">
|
|
|
|
<a href="./#ios系统信任ca证书">
|
|
|
|
|
|
<div class="summary-title-span iOS系统信任CA证书">
|
|
iOS系统信任CA证书
|
|
</div>
|
|
|
|
|
|
</a>
|
|
|
|
|
|
|
|
</li>
|
|
|
|
<li class="chapter " data-level="1.7.6" data-path="./">
|
|
|
|
<a href="./#ios--103信任ca证书">
|
|
|
|
|
|
<div class="summary-title-span iOS >= 10.3信任CA证书">
|
|
iOS >= 10.3信任CA证书
|
|
</div>
|
|
|
|
|
|
</a>
|
|
|
|
|
|
|
|
</li>
|
|
|
|
<li class="chapter " data-level="1.7.7" data-path="./">
|
|
|
|
<a href="./#配置iosandroid系统代理">
|
|
|
|
|
|
<div class="summary-title-span 配置iOS/Android系统代理">
|
|
配置iOS/Android系统代理
|
|
</div>
|
|
|
|
|
|
</a>
|
|
|
|
|
|
|
|
</li>
|
|
|
|
|
|
</ul>
|
|
|
|
</li>
|
|
|
|
<li class="chapter " data-level="1.8" data-path="./">
|
|
|
|
<a href="./#faq">
|
|
|
|
|
|
<div class="summary-title-span FAQ">
|
|
FAQ
|
|
</div>
|
|
|
|
|
|
</a>
|
|
|
|
|
|
|
|
</li>
|
|
|
|
|
|
|
|
|
|
<li class="divider"></li>
|
|
|
|
<li>
|
|
<a href="https://www.gitbook.com" target="blank" class="gitbook-link">
|
|
Published with GitBook
|
|
</a>
|
|
</li>
|
|
</ul>
|
|
|
|
|
|
</nav>
|
|
|
|
|
|
</div>
|
|
|
|
<div class="book-body">
|
|
|
|
<div class="body-inner">
|
|
|
|
|
|
|
|
<div class="book-header" role="navigation">
|
|
|
|
|
|
<!-- Title -->
|
|
<h1>
|
|
<i class="fa fa-circle-o-notch fa-spin"></i>
|
|
<a href="." >简介</a>
|
|
</h1>
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div class="page-wrapper" tabindex="-1" role="main">
|
|
<div class="page-inner">
|
|
|
|
<div id="book-search-results">
|
|
<div class="search-noresults">
|
|
|
|
<section class="normal markdown-section">
|
|
|
|
<h1 id="anyproxy">AnyProxy</h1>
|
|
<blockquote>
|
|
<p>本文档的适用范围是AnyProxy 4.0,欢迎提供反馈</p>
|
|
</blockquote>
|
|
<p>Ref: <a href="../en">English Doc</a></p>
|
|
<p>AnyProxy是一个开放式的HTTP代理服务器。</p>
|
|
<p>Github主页:<a href="https://github.com/alibaba/anyproxy/tree/4.x" target="_blank">https://github.com/alibaba/anyproxy/tree/4.x</a></p>
|
|
<p>主要特性包括:</p>
|
|
<ul>
|
|
<li>基于Node.js,开放二次开发能力,允许自定义请求处理逻辑</li>
|
|
<li>支持Https的解析</li>
|
|
<li>提供GUI界面,用以观察请求</li>
|
|
</ul>
|
|
<p>相比3.x版本,AnyProxy 4.0的主要变化:</p>
|
|
<ul>
|
|
<li>规则文件(Rule)全面支持Promise和Generator</li>
|
|
<li>简化了规则文件内的接口</li>
|
|
<li>Web版界面重构</li>
|
|
</ul>
|
|
<p><img src="https://gw.alipayobjects.com/zos/rmsportal/JoxHUbVhXNedsPUUilnj.gif" width="1275px"></p>
|
|
<h1 id="快速开始">快速开始</h1>
|
|
<h2 id="作为全局模块">作为全局模块</h2>
|
|
<h3 id="安装">安装</h3>
|
|
<p>对于Debian或者Ubuntu系统,在安装AnyProxy之前,可能还需要安装 <code>nodejs-legacy</code></p>
|
|
<pre><code class="lang-bash">sudo apt-get install nodejs-legacy
|
|
</code></pre>
|
|
<p>然后,安装AnyProxy</p>
|
|
<pre><code class="lang-bash">npm install -g anyproxy
|
|
</code></pre>
|
|
<h3 id="启动">启动</h3>
|
|
<ul>
|
|
<li>命令行启动AnyProxy,默认端口号8001</li>
|
|
</ul>
|
|
<pre><code class="lang-bash">anyproxy
|
|
</code></pre>
|
|
<ul>
|
|
<li>启动后将终端http代理服务器配置为127.0.0.1:8001即可</li>
|
|
<li>访问<a href="http://127.0.0.1:8002" target="_blank">http://127.0.0.1:8002</a> ,web界面上能看到所有的请求信息</li>
|
|
</ul>
|
|
<h3 id="其他命令">其他命令</h3>
|
|
<ul>
|
|
<li>配置启动端口,如1080端口启动</li>
|
|
</ul>
|
|
<pre><code class="lang-bash">anyproxy --port 1080
|
|
</code></pre>
|
|
<h2 id="作为npm模块使用">作为npm模块使用</h2>
|
|
<p>AnyProxy可以作为一个npm模块使用,整合进其他工具。</p>
|
|
<blockquote>
|
|
<p>如要启用https解析,请在代理服务器启动前自行调用<code>AnyProxy.utils.certMgr</code>相关方法生成证书,并引导用户信任安装。或引导用户使用<code>anyproxy-ca</code>方法。</p>
|
|
</blockquote>
|
|
<ul>
|
|
<li>引入</li>
|
|
</ul>
|
|
<pre><code class="lang-bash">npm i anyproxy --save
|
|
</code></pre>
|
|
<ul>
|
|
<li>使用举例</li>
|
|
</ul>
|
|
<pre><code class="lang-js"><span class="hljs-keyword">const</span> AnyProxy = <span class="hljs-built_in">require</span>(<span class="hljs-string">'anyproxy'</span>);
|
|
<span class="hljs-keyword">const</span> options = {
|
|
port: <span class="hljs-number">8001</span>,
|
|
rule: <span class="hljs-built_in">require</span>(<span class="hljs-string">'myRuleModule'</span>),
|
|
webInterface: {
|
|
enable: <span class="hljs-literal">true</span>,
|
|
webPort: <span class="hljs-number">8002</span>,
|
|
wsPort: <span class="hljs-number">8003</span>,
|
|
},
|
|
throttle: <span class="hljs-number">10000</span>,
|
|
forceProxyHttps: <span class="hljs-literal">false</span>,
|
|
silent: <span class="hljs-literal">false</span>
|
|
};
|
|
<span class="hljs-keyword">const</span> proxyServer = <span class="hljs-keyword">new</span> AnyProxy.ProxyServer(options);
|
|
|
|
proxyServer.on(<span class="hljs-string">'ready'</span>, () => { <span class="hljs-comment">/* */</span> });
|
|
proxyServer.on(<span class="hljs-string">'error'</span>, (e) => { <span class="hljs-comment">/* */</span> });
|
|
proxyServer.start();
|
|
|
|
<span class="hljs-comment">//when finished</span>
|
|
proxyServer.close();
|
|
</code></pre>
|
|
<ul>
|
|
<li><p>Class: AnyProxy.proxyServer</p>
|
|
<ul>
|
|
<li><p>创建代理服务器</p>
|
|
<pre><code class="lang-js"><span class="hljs-keyword">const</span> proxy = <span class="hljs-keyword">new</span> AnyProxy.proxyServer(options)
|
|
</code></pre>
|
|
</li>
|
|
<li><p><code>options</code></p>
|
|
<ul>
|
|
<li><code>port</code> {number} 必选,代理服务器端口</li>
|
|
<li><code>rule</code> {object} 自定义规则模块</li>
|
|
<li><code>throttle</code> {number} 限速值,单位kb/s,默认不限速</li>
|
|
<li><code>forceProxyHttps</code> {boolean} 是否强制拦截所有的https,忽略规则模块的返回,默认<code>false</code></li>
|
|
<li><code>silent</code> {boolean} 是否屏蔽所有console输出,默认<code>false</code></li>
|
|
<li><code>dangerouslyIgnoreUnauthorized</code> {boolean} 是否忽略请求中的证书错误,默认<code>false</code></li>
|
|
<li><code>webInterface</code> {object} web版界面配置<ul>
|
|
<li><code>enable</code> {boolean} 是否启用web版界面,默认<code>false</code></li>
|
|
<li><code>webPort</code> {number} web版界面端口号,默认<code>8002</code></li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
</li>
|
|
<li><p>Event: <code>ready</code></p>
|
|
<ul>
|
|
<li>代理服务器启动完成</li>
|
|
<li>示例</li>
|
|
</ul>
|
|
<pre><code class="lang-js">proxy.on(<span class="hljs-string">'ready'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{ })
|
|
</code></pre>
|
|
</li>
|
|
<li><p>Event: <code>error</code></p>
|
|
<ul>
|
|
<li>代理服务器发生错误</li>
|
|
<li>示例</li>
|
|
</ul>
|
|
<pre><code class="lang-js">proxy.on(<span class="hljs-string">'error'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{ })
|
|
</code></pre>
|
|
</li>
|
|
<li><p>Method: <code>start</code></p>
|
|
<ul>
|
|
<li>启动代理服务器</li>
|
|
<li>示例</li>
|
|
</ul>
|
|
<pre><code class="lang-js">proxy.start();
|
|
</code></pre>
|
|
</li>
|
|
<li><p>Method: <code>close</code></p>
|
|
<ul>
|
|
<li>关闭代理服务器</li>
|
|
<li>示例</li>
|
|
</ul>
|
|
<pre><code class="lang-js">proxy.close();
|
|
</code></pre>
|
|
</li>
|
|
</ul>
|
|
</li>
|
|
<li><p>AnyProxy.utils.systemProxyMgr</p>
|
|
<ul>
|
|
<li>管理系统的全局代理配置,方法调用时可能会弹出密码框</li>
|
|
<li>使用示例</li>
|
|
</ul>
|
|
<pre><code class="lang-js"><span class="hljs-comment">// 配置127.0.0.1:8001为全局http代理服务器</span>
|
|
AnyProxy.utils.systemProxyMgr.enableGlobalProxy(<span class="hljs-string">'127.0.0.1'</span>, <span class="hljs-string">'8001'</span>);
|
|
|
|
<span class="hljs-comment">// 关闭全局代理服务器</span>
|
|
AnyProxy.utils.systemProxyMgr.disableGlobalProxy();
|
|
</code></pre>
|
|
</li>
|
|
<li><p>AnyProxy.utils.certMgr</p>
|
|
<ul>
|
|
<li>管理AnyProxy的证书</li>
|
|
<li><code>AnyProxy.utils.certMgr.ifRootCAFileExists()</code><ul>
|
|
<li>校验系统内是否存在AnyProxy的根证书</li>
|
|
</ul>
|
|
</li>
|
|
<li><code>AnyProxy.utils.certMgr.generateRootCA(callback)</code><ul>
|
|
<li>生成AnyProxy的rootCA,完成后请引导用户信任.crt文件</li>
|
|
</ul>
|
|
</li>
|
|
<li>样例</li>
|
|
</ul>
|
|
<pre><code class="lang-js"> <span class="hljs-keyword">const</span> AnyProxy = <span class="hljs-built_in">require</span>(<span class="hljs-string">'AnyProxy'</span>);
|
|
<span class="hljs-keyword">const</span> exec = <span class="hljs-built_in">require</span>(<span class="hljs-string">'child_process'</span>).exec;
|
|
|
|
<span class="hljs-keyword">if</span> (!AnyProxy.utils.certMgr.ifRootCAFileExists()) {
|
|
AnyProxy.utils.certMgr.generateRootCA((error, keyPath) => {
|
|
<span class="hljs-comment">// let users to trust this CA before using proxy</span>
|
|
<span class="hljs-keyword">if</span> (!error) {
|
|
<span class="hljs-keyword">const</span> certDir = <span class="hljs-built_in">require</span>(<span class="hljs-string">'path'</span>).dirname(keyPath);
|
|
<span class="hljs-built_in">console</span>.log(<span class="hljs-string">'The cert is generated at'</span>, certDir);
|
|
<span class="hljs-keyword">const</span> isWin = <span class="hljs-regexp">/^win/</span>.test(process.platform);
|
|
<span class="hljs-keyword">if</span> (isWin) {
|
|
exec(<span class="hljs-string">'start .'</span>, { cwd: certDir });
|
|
} <span class="hljs-keyword">else</span> {
|
|
exec(<span class="hljs-string">'open .'</span>, { cwd: certDir });
|
|
}
|
|
} <span class="hljs-keyword">else</span> {
|
|
<span class="hljs-built_in">console</span>.error(<span class="hljs-string">'error when generating rootCA'</span>, error);
|
|
}
|
|
});
|
|
}
|
|
</code></pre>
|
|
</li>
|
|
</ul>
|
|
<h1 id="代理https">代理HTTPS</h1>
|
|
<ul>
|
|
<li>AnyProxy默认不对https请求做处理,如需看到明文信息,需要配置CA证书</li>
|
|
</ul>
|
|
<blockquote>
|
|
<p>解析https请求的原理是中间人攻击(man-in-the-middle),用户必须信任AnyProxy生成的CA证书,才能进行后续流程</p>
|
|
</blockquote>
|
|
<ul>
|
|
<li>生成证书并解析所有https请求</li>
|
|
</ul>
|
|
<pre><code class="lang-bash">anyproxy-ca <span class="hljs-comment">#生成rootCA证书,生成后需要手动信任</span>
|
|
anyproxy --intercept <span class="hljs-comment">#启动AnyProxy,并解析所有https请求</span>
|
|
</code></pre>
|
|
<ul>
|
|
<li><a href="#证书配置">附录:如何信任CA证书</a></li>
|
|
</ul>
|
|
<h1 id="rule模块">rule模块</h1>
|
|
<p>AnyProxy提供了二次开发的能力,你可以用js编写自己的规则模块(rule),来自定义网络请求的处理逻辑。</p>
|
|
<blockquote>
|
|
<p>注意:引用规则前,请务必确保文件来源可靠,以免发生安全问题</p>
|
|
</blockquote>
|
|
<p>规则模块的能力范围包括:</p>
|
|
<ul>
|
|
<li>拦截并修改正在发送的请求<ul>
|
|
<li>可修改内容包括请求头(request header),请求体(request body),甚至是请求的目标地址等</li>
|
|
</ul>
|
|
</li>
|
|
<li>拦截并修改服务端响应<ul>
|
|
<li>可修改的内容包括http状态码(status code)、响应头(response header)、响应内容等</li>
|
|
</ul>
|
|
</li>
|
|
<li>拦截https请求,对内容做修改<ul>
|
|
<li>本质是中间人攻击(man-in-the-middle attack),需要客户端提前信任AnyProxy生成的CA</li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
<h3 id="开发示例">开发示例</h3>
|
|
<ul>
|
|
<li><p>举例</p>
|
|
<ul>
|
|
<li>需要编写一个规则模块,在 GET <a href="http://httpbin.org/user-agent" target="_blank">http://httpbin.org/user-agent</a> 的返回值里加上测试信息,并延迟5秒返回</li>
|
|
</ul>
|
|
</li>
|
|
<li><p>Step 1,编写规则</p>
|
|
<pre><code class="lang-js"><span class="hljs-comment">// file: sample.js</span>
|
|
<span class="hljs-built_in">module</span>.exports = {
|
|
summary: <span class="hljs-string">'a rule to hack response'</span>,
|
|
*beforeSendResponse(requestDetail, responseDetail) {
|
|
<span class="hljs-keyword">if</span> (requestDetail.url === <span class="hljs-string">'http://httpbin.org/user-agent'</span>) {
|
|
<span class="hljs-keyword">const</span> newResponse = responseDetail.response;
|
|
newResponse.body += <span class="hljs-string">'- AnyProxy Hacked!'</span>;
|
|
|
|
<span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Promise</span>((resolve, reject) => {
|
|
setTimeout(() => { <span class="hljs-comment">// delay</span>
|
|
resolve({ response: newResponse });
|
|
}, <span class="hljs-number">5000</span>);
|
|
});
|
|
}
|
|
},
|
|
};
|
|
</code></pre>
|
|
</li>
|
|
<li><p>Step 2, 启动AnyProxy,加载规则</p>
|
|
<ul>
|
|
<li>运行 <code>anyproxy --rule sample.js</code></li>
|
|
</ul>
|
|
</li>
|
|
<li><p>Step 3, 测试规则</p>
|
|
<ul>
|
|
<li><p>用curl测试</p>
|
|
<pre><code class="lang-bash">curl http://httpbin.org/user-agent --proxy http://127.0.0.1:8001
|
|
</code></pre>
|
|
</li>
|
|
<li><p>用浏览器测试:配置浏览器http代理为 127.0.0.1:8001,访问 <a href="http://httpbin.org/user-agent" target="_blank">http://httpbin.org/user-agent</a></p>
|
|
</li>
|
|
<li><p>经过代理服务器后,期望的返回如下</p>
|
|
</li>
|
|
</ul>
|
|
<pre><code>{
|
|
"user-agent": "curl/7.43.0"
|
|
}
|
|
- AnyProxy Hacked!
|
|
</code></pre></li>
|
|
<li><p>Step 4, 查看请求信息</p>
|
|
<ul>
|
|
<li>浏览器访问<a href="http://127.0.0.1:8002" target="_blank">http://127.0.0.1:8002</a> ,界面上能看到刚才的请求信息</li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
<h3 id="处理流程">处理流程</h3>
|
|
<ul>
|
|
<li>处理流程图如下</li>
|
|
</ul>
|
|
<p><img src="https://zos.alipayobjects.com/rmsportal/TWyNuSJtEZBdrdcOMRjE.png" width="550"></p>
|
|
<ul>
|
|
<li><p>当http请求经过代理服务器时,具体处理过程是:</p>
|
|
<ul>
|
|
<li>收集请求所有请求参数,包括method, header, body等</li>
|
|
<li>AnyProxy调用规则模块<code>beforeSendRequest</code>方法,由模块做处理,返回新的请求参数,或返回响应内容</li>
|
|
<li>如果<code>beforeSendRequest</code>返回了响应内容,则立即把此响应返回到客户端(而不再发送到真正的服务端),流程结束。</li>
|
|
<li>根据请求参数,向服务端发出请求,接收服务端响应。</li>
|
|
<li>调用规则模块<code>beforeSendResponse</code>方法,由模块对响应内容进行处理</li>
|
|
<li>把响应信息返回给客户端</li>
|
|
</ul>
|
|
</li>
|
|
<li><p>当代理服务器收到https请求时,AnyProxy可以替换证书,对请求做明文解析。</p>
|
|
<ul>
|
|
<li>调用规则模块<code>beforeDealHttpsRequest</code>方法,如果返回<code>true</code>,会明文解析这个请求,其他请求不处理</li>
|
|
<li>被明文解析后的https请求,处理流程同http一致。未明文解析请求不会再进入规则模块做处理。</li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
<h3 id="如何引用">如何引用</h3>
|
|
<p>如下几种方案都可以用来引用规则模块:</p>
|
|
<ul>
|
|
<li>使用本地路径<pre><code class="lang-bash">anyproxy --rule ./rule.js
|
|
</code></pre>
|
|
</li>
|
|
<li><p>使用在线地址</p>
|
|
<pre><code class="lang-bash">anyproxy --rule https://sample.com/rule.js
|
|
</code></pre>
|
|
</li>
|
|
<li><p>使用npm包</p>
|
|
<ul>
|
|
<li>AnyProxy使用<code>require()</code>加载本地规则,你可以在参数里传入一个本地的npm包路径,或是某个全局安装的npm包</li>
|
|
</ul>
|
|
<pre><code class="lang-bash">anyproxy --rule ./myRulePkg/ <span class="hljs-comment">#本地包</span>
|
|
npm i -g myRulePkg && anyproxy --rule myRulePkg <span class="hljs-comment">#全局包</span>
|
|
</code></pre>
|
|
</li>
|
|
</ul>
|
|
<h1 id="rule接口文档">rule接口文档</h1>
|
|
<p>规则模块应该符合cmd规范,一个典型的规则模块代码结构如下。模块中所有方法都是可选的,只需实现业务感兴趣的部分即可。</p>
|
|
<pre><code class="lang-js"><span class="hljs-built_in">module</span>.exports = {
|
|
<span class="hljs-comment">// 模块介绍</span>
|
|
summary: <span class="hljs-string">'my customized rule for AnyProxy'</span>,
|
|
<span class="hljs-comment">// 发送请求前拦截处理</span>
|
|
*beforeSendRequest(requestDetail) { <span class="hljs-comment">/* ... */</span> },
|
|
<span class="hljs-comment">// 发送响应前处理</span>
|
|
*beforeSendResponse(requestDetail, responseDetail) { <span class="hljs-comment">/* ... */</span> },
|
|
<span class="hljs-comment">// 是否处理https请求</span>
|
|
*beforeDealHttpsRequest(requestDetail) { <span class="hljs-comment">/* ... */</span> },
|
|
<span class="hljs-comment">// 请求出错的事件</span>
|
|
*onError(requestDetail, error) { <span class="hljs-comment">/* ... */</span> },
|
|
<span class="hljs-comment">// https连接服务器出错</span>
|
|
*onConnectError(requestDetail, error) { <span class="hljs-comment">/* ... */</span> }
|
|
};
|
|
</code></pre>
|
|
<blockquote>
|
|
<p>规则文件中,除了summary,都是由 <a href="https://www.npmjs.com/package/co" target="_blank">co</a> 驱动的,函数需要满足yieldable。可以返回promise或使用generator函数。</p>
|
|
</blockquote>
|
|
<h3 id="summary">summary</h3>
|
|
<h4 id="summary-string--summarystring">summary(): string | summary:string</h4>
|
|
<ul>
|
|
<li>规则模块的介绍文案,用于AnyProxy提示用户, 可以是一个函数,也可以是一个普通的字符串</li>
|
|
</ul>
|
|
<h3 id="beforesendrequest">beforeSendRequest</h3>
|
|
<h4 id="beforesendrequestrequestdetail">beforeSendRequest(requestDetail)</h4>
|
|
<ul>
|
|
<li>AnyProxy向服务端发送请求前,会调用<code>beforeSendRequest</code>,并带上参数<code>requestDetail</code></li>
|
|
<li><code>requestDetail</code><ul>
|
|
<li><code>protocol</code> {string} 请求使用的协议,http或者https</li>
|
|
<li><code>requestOptions</code> {object} 即将发送的请求配置,供require('http').request作为使用。详见:<a href="https://nodejs.org/api/http.html#http_http_request_options_callback" target="_blank">https://nodejs.org/api/http.html#http_http_request_options_callback</a></li>
|
|
<li><code>requestData</code> {object} 请求Body</li>
|
|
<li><code>url</code> {string} 请求url</li>
|
|
<li><code>_req</code> {object} 请求的原始request</li>
|
|
</ul>
|
|
</li>
|
|
<li><p>举例:请求 <em>anyproxy.io</em> 时,<code>requestDetail</code>参数内容大致如下</p>
|
|
<pre><code class="lang-js">{
|
|
protocol: <span class="hljs-string">'http'</span>,
|
|
url: <span class="hljs-string">'http://anyproxy.io/'</span>,
|
|
requestOptions: {
|
|
hostname: <span class="hljs-string">'anyproxy.io'</span>,
|
|
port: <span class="hljs-number">80</span>,
|
|
path: <span class="hljs-string">'/'</span>,
|
|
method: <span class="hljs-string">'GET'</span>,
|
|
headers: {
|
|
Host: <span class="hljs-string">'anyproxy.io'</span>,
|
|
<span class="hljs-string">'Proxy-Connection'</span>: <span class="hljs-string">'keep-alive'</span>,
|
|
<span class="hljs-string">'User-Agent'</span>: <span class="hljs-string">'...'</span>
|
|
}
|
|
},
|
|
requestData: <span class="hljs-string">'...'</span>,
|
|
_req: { <span class="hljs-comment">/* ... */</span>}
|
|
}
|
|
</code></pre>
|
|
</li>
|
|
<li><p>以下几种返回都是合法的</p>
|
|
<ul>
|
|
<li>不做任何处理,返回null</li>
|
|
</ul>
|
|
<pre><code class="lang-js"><span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>;
|
|
</code></pre>
|
|
<ul>
|
|
<li>修改请求协议,如强制改用https发起请求</li>
|
|
</ul>
|
|
<pre><code class="lang-js"><span class="hljs-keyword">return</span> {
|
|
protocol: <span class="hljs-string">'https'</span>
|
|
};
|
|
</code></pre>
|
|
<ul>
|
|
<li>修改请求参数</li>
|
|
</ul>
|
|
<pre><code class="lang-js"><span class="hljs-keyword">var</span> newOption = <span class="hljs-built_in">Object</span>.assign({}, requestDetail.requestOptions);
|
|
newOption.path = <span class="hljs-string">'/redirect/to/another/path'</span>;
|
|
<span class="hljs-keyword">return</span> {
|
|
requestOptions: newOption
|
|
};
|
|
</code></pre>
|
|
<ul>
|
|
<li>修改请求body</li>
|
|
</ul>
|
|
<pre><code class="lang-js"><span class="hljs-keyword">return</span> {
|
|
requestData: <span class="hljs-string">'my new request data'</span>
|
|
<span class="hljs-comment">//这里也可以同时加上requestOptions</span>
|
|
};
|
|
</code></pre>
|
|
<ul>
|
|
<li>直接返回客户端,不再发起请求,其中<code>statusCode</code> <code>header</code> 是必选字段</li>
|
|
</ul>
|
|
<pre><code class="lang-js"><span class="hljs-keyword">return</span> {
|
|
response: {
|
|
statusCode: <span class="hljs-number">200</span>,
|
|
header: { <span class="hljs-string">'content-type'</span>: <span class="hljs-string">'text/html'</span> },
|
|
body: <span class="hljs-string">'this could be a <string> or <buffer>'</span>
|
|
}
|
|
};
|
|
</code></pre>
|
|
</li>
|
|
</ul>
|
|
<h3 id="beforesendresponse">beforeSendResponse</h3>
|
|
<h4 id="beforesendresponserequestdetail-responsedetail">beforeSendResponse(requestDetail, responseDetail)</h4>
|
|
<ul>
|
|
<li>AnyProxy向客户端发送请求前,会调用<code>beforeSendResponse</code>,并带上参数<code>requestDetail</code> <code>responseDetail</code></li>
|
|
<li><code>requestDetail</code> 同<code>beforeSendRequest</code>中的参数</li>
|
|
<li><code>responseDetail</code><ul>
|
|
<li><code>response</code> {object} 服务端的返回信息,包括<code>statusCode</code> <code>header</code> <code>body</code>三个字段</li>
|
|
<li><code>_res</code> {object} 原始的服务端返回对象</li>
|
|
</ul>
|
|
</li>
|
|
<li><p>举例,请求 <em>anyproxy.io</em> 时,<code>responseDetail</code>参数内容大致如下</p>
|
|
<pre><code class="lang-js">{
|
|
response: {
|
|
statusCode: <span class="hljs-number">200</span>,
|
|
header: {
|
|
<span class="hljs-string">'Content-Type'</span>: <span class="hljs-string">'image/gif'</span>,
|
|
Connection: <span class="hljs-string">'close'</span>,
|
|
<span class="hljs-string">'Cache-Control'</span>: <span class="hljs-string">'...'</span>
|
|
},
|
|
body: <span class="hljs-string">'...'</span>
|
|
},
|
|
_res: { <span class="hljs-comment">/* ... */</span> }
|
|
}
|
|
</code></pre>
|
|
</li>
|
|
<li><p>以下几种返回都是合法的</p>
|
|
<ul>
|
|
<li>不做任何处理,返回null</li>
|
|
</ul>
|
|
<pre><code class="lang-js"><span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>;
|
|
</code></pre>
|
|
<ul>
|
|
<li>修改返回的状态码</li>
|
|
</ul>
|
|
<pre><code class="lang-js"><span class="hljs-keyword">var</span> newResponse = <span class="hljs-built_in">Object</span>.assign({}, responseDetail.response);
|
|
newResponse.statusCode = <span class="hljs-number">404</span>;
|
|
<span class="hljs-keyword">return</span> {
|
|
response: newResponse
|
|
};
|
|
</code></pre>
|
|
<ul>
|
|
<li>修改返回的内容</li>
|
|
</ul>
|
|
<pre><code class="lang-js"><span class="hljs-keyword">var</span> newResponse = <span class="hljs-built_in">Object</span>.assign({}, responseDetail.response);
|
|
newResponse.body += <span class="hljs-string">'--from anyproxy--'</span>;
|
|
<span class="hljs-keyword">return</span> {
|
|
response: newResponse
|
|
};
|
|
</code></pre>
|
|
</li>
|
|
</ul>
|
|
<h3 id="beforedealhttpsrequest">beforeDealHttpsRequest</h3>
|
|
<h4 id="beforedealhttpsrequestrequestdetail">beforeDealHttpsRequest(requestDetail)</h4>
|
|
<ul>
|
|
<li>AnyProxy收到https请求时,会调用<code>beforeDealHttpsRequest</code>,并带上参数<code>requestDetail</code></li>
|
|
<li>如果配置了全局解析https的参数,则AnyProxy会略过这个调用</li>
|
|
<li>只有返回<code>true</code>时,AnyProxy才会尝试替换证书、解析https。否则只做数据流转发,无法看到明文数据。</li>
|
|
<li>注意:https over http的代理模式中,这里的request是CONNECT请求</li>
|
|
<li><code>requestDetail</code><ul>
|
|
<li><code>host</code> {string} 请求目标的Host,受制于协议,这里无法获取完整url</li>
|
|
<li><code>_req</code> {object} 请求的原始request</li>
|
|
</ul>
|
|
</li>
|
|
<li>返回值<ul>
|
|
<li><code>true</code>或者<code>false</code>,表示是否需要AnyProxy替换证书并解析https</li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
<h3 id="onerror">onError</h3>
|
|
<h4 id="onerrorrequestdetail-error">onError(requestDetail, error)</h4>
|
|
<ul>
|
|
<li>在请求处理过程中发生错误时,AnyProxy会调用<code>onError</code>方法,并提供对应的错误信息</li>
|
|
<li>多数场景下,错误会在请求目标服务器的时候发生,比如DNS解析失败、请求超时等</li>
|
|
<li><code>requestDetail</code> 同<code>beforeSendRequest</code>中的参数</li>
|
|
<li><p>以下几种返回都是合法的</p>
|
|
<ul>
|
|
<li>不做任何处理。此时AnyProxy会返回一个默认的错误页。</li>
|
|
</ul>
|
|
<pre><code class="lang-js"><span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>;
|
|
</code></pre>
|
|
<ul>
|
|
<li>返回自定义错误页</li>
|
|
</ul>
|
|
<pre><code class="lang-js"><span class="hljs-keyword">return</span> {
|
|
response: {
|
|
statusCode: <span class="hljs-number">200</span>,
|
|
header: { <span class="hljs-string">'content-type'</span>: <span class="hljs-string">'text/html'</span> },
|
|
body: <span class="hljs-string">'this could be a <string> or <buffer>'</span>
|
|
}
|
|
};
|
|
</code></pre>
|
|
</li>
|
|
</ul>
|
|
<h3 id="onconnecterror">onConnectError</h3>
|
|
<h4 id="onconnecterrorrequestdetail-error">onConnectError(requestDetail, error)</h4>
|
|
<ul>
|
|
<li>AnyProxy在与目标HTTPS服务器建立连接的过程中,如果发生错误,AnyProxy会调用这个方法</li>
|
|
<li><code>requestDetail</code> 同<code>beforeDealHttpsRequest</code>中的参数</li>
|
|
<li>此处无法控制向客户端的返回信息,无需返回值。</li>
|
|
</ul>
|
|
<h1 id="rule样例">rule样例</h1>
|
|
<ul>
|
|
<li>这里提供一些样例,来讲解规则模块的常见用法</li>
|
|
<li>你可以通过 <code>anyproxy --rule http://....js</code> 来加载模块并体验</li>
|
|
<li>用curl发请求测试的方法如下<ul>
|
|
<li>直接请求服务器:<code>curl http://httpbin.org/</code></li>
|
|
<li>通过代理服务器请求:<code>curl http://httpbin.org/ --proxy http://127.0.0.1:8001</code></li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
<h3 id="使用本地数据">使用本地数据</h3>
|
|
<ul>
|
|
<li>拦截发送到 <a href="http://httpbin.org" target="_blank">http://httpbin.org</a> 的请求,使用本地数据代替服务端返回</li>
|
|
</ul>
|
|
<pre><code class="lang-bash">anyproxy --rule rule_sample/sample_use_<span class="hljs-built_in">local</span>_response.js
|
|
</code></pre>
|
|
<pre><code class="lang-js"><span class="hljs-comment">/*
|
|
sample:
|
|
intercept all requests toward httpbin.org, use a local response
|
|
test:
|
|
curl http://httpbin.org/user-agent --proxy http://127.0.0.1:8001
|
|
*/</span>
|
|
<span class="hljs-built_in">module</span>.exports = {
|
|
*beforeSendRequest(requestDetail) {
|
|
<span class="hljs-keyword">const</span> localResponse = {
|
|
statusCode: <span class="hljs-number">200</span>,
|
|
header: { <span class="hljs-string">'Content-Type'</span>: <span class="hljs-string">'application/json'</span> },
|
|
body: <span class="hljs-string">'{"hello": "this is local response"}'</span>
|
|
};
|
|
<span class="hljs-keyword">if</span> (requestDetail.url.indexOf(<span class="hljs-string">'http://httpbin.org'</span>) === <span class="hljs-number">0</span>) {
|
|
<span class="hljs-keyword">return</span> {
|
|
response: localResponse
|
|
};
|
|
}
|
|
},
|
|
};
|
|
</code></pre>
|
|
<h3 id="修改请求头">修改请求头</h3>
|
|
<ul>
|
|
<li>修改发送到 httpbin.org 的user-agent</li>
|
|
</ul>
|
|
<pre><code class="lang-bash">anyproxy --rule rule_sample/sample_modify_request_header.js
|
|
</code></pre>
|
|
<pre><code class="lang-js"><span class="hljs-comment">/*
|
|
sample:
|
|
modify the user-agent in requests toward httpbin.org
|
|
test:
|
|
curl http://httpbin.org/user-agent --proxy http://127.0.0.1:8001
|
|
*/</span>
|
|
<span class="hljs-built_in">module</span>.exports = {
|
|
*beforeSendRequest(requestDetail) {
|
|
<span class="hljs-keyword">if</span> (requestDetail.url.indexOf(<span class="hljs-string">'http://httpbin.org'</span>) === <span class="hljs-number">0</span>) {
|
|
<span class="hljs-keyword">const</span> newRequestOptions = requestDetail.requestOptions;
|
|
newRequestOptions.headers[<span class="hljs-string">'User-Agent'</span>] = <span class="hljs-string">'AnyProxy/0.0.0'</span>;
|
|
<span class="hljs-keyword">return</span> {
|
|
requestOptions: newRequestOptions
|
|
};
|
|
}
|
|
},
|
|
};
|
|
</code></pre>
|
|
<h3 id="修改请求数据">修改请求数据</h3>
|
|
<ul>
|
|
<li>修改发送到 <a href="http://httpbin.org/post" target="_blank">http://httpbin.org/post</a> 的post数据</li>
|
|
</ul>
|
|
<pre><code class="lang-bash">anyproxy --rule rule_sample/sample_modify_request_data.js
|
|
</code></pre>
|
|
<pre><code class="lang-js"><span class="hljs-comment">/*
|
|
sample:
|
|
modify the post data towards http://httpbin.org/post
|
|
test:
|
|
curl -H "Content-Type: text/plain" -X POST -d 'original post data' http://httpbin.org/post --proxy http://127.0.0.1:8001
|
|
expected response:
|
|
{ "data": "i-am-anyproxy-modified-post-data" }
|
|
*/</span>
|
|
<span class="hljs-built_in">module</span>.exports = {
|
|
summary: <span class="hljs-string">'Rule to modify request data'</span>,
|
|
*beforeSendRequest(requestDetail) {
|
|
<span class="hljs-keyword">if</span> (requestDetail.url.indexOf(<span class="hljs-string">'http://httpbin.org/post'</span>) === <span class="hljs-number">0</span>) {
|
|
<span class="hljs-keyword">return</span> {
|
|
requestData: <span class="hljs-string">'i-am-anyproxy-modified-post-data'</span>
|
|
};
|
|
}
|
|
},
|
|
};
|
|
</code></pre>
|
|
<h3 id="修改请求的目标地址">修改请求的目标地址</h3>
|
|
<ul>
|
|
<li>把所有发送到 <a href="http://httpbin.org/" target="_blank">http://httpbin.org/</a> 的请求全部改到 <a href="http://httpbin.org/user-agent" target="_blank">http://httpbin.org/user-agent</a></li>
|
|
</ul>
|
|
<pre><code class="lang-bash">anyproxy --rule rule_sample/sample_modify_request_path.js
|
|
</code></pre>
|
|
<pre><code class="lang-js"><span class="hljs-comment">/*
|
|
sample:
|
|
redirect all https://httpbin.org/user-agent requests to http://localhost:8008/index.html
|
|
test:
|
|
curl https://httpbin.org/user-agent --proxy http://127.0.0.1:8001
|
|
expected response:
|
|
'hello world' from 127.0.0.1:8001/index.html
|
|
*/</span>
|
|
<span class="hljs-built_in">module</span>.exports = {
|
|
*beforeSendRequest(requestDetail) {
|
|
<span class="hljs-keyword">if</span> (requestDetail.url.indexOf(<span class="hljs-string">'https://httpbin.org/user-agent'</span>) === <span class="hljs-number">0</span>) {
|
|
<span class="hljs-keyword">const</span> newRequestOptions = requestDetail.requestOptions;
|
|
requestDetail.protocol = <span class="hljs-string">'http'</span>;
|
|
newRequestOptions.hostname = <span class="hljs-string">'127.0.0.1'</span>
|
|
newRequestOptions.port = <span class="hljs-string">'8008'</span>;
|
|
newRequestOptions.path = <span class="hljs-string">'/index.html'</span>;
|
|
newRequestOptions.method = <span class="hljs-string">'GET'</span>;
|
|
<span class="hljs-keyword">return</span> requestDetail;
|
|
}
|
|
},
|
|
*beforeDealHttpsRequest(requestDetail) {
|
|
<span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
|
|
}
|
|
};
|
|
</code></pre>
|
|
<h3 id="修改请求协议">修改请求协议</h3>
|
|
<ul>
|
|
<li>把用http协议请求的 <a href="http://httpbin.org" target="_blank">http://httpbin.org</a> 改成https并发送</li>
|
|
</ul>
|
|
<pre><code class="lang-bash">anyproxy --rule rule_sample/sample_modify_request_protocol.js
|
|
</code></pre>
|
|
<pre><code class="lang-js"><span class="hljs-comment">/*
|
|
sample:
|
|
redirect all http requests of httpbin.org to https
|
|
test:
|
|
curl 'http://httpbin.org/get?show_env=1' --proxy http://127.0.0.1:8001
|
|
expected response:
|
|
{ "X-Forwarded-Protocol": "https" }
|
|
*/</span>
|
|
<span class="hljs-built_in">module</span>.exports = {
|
|
*beforeSendRequest(requestDetail) {
|
|
<span class="hljs-keyword">if</span> (requestDetail.url.indexOf(<span class="hljs-string">'http://httpbin.org'</span>) === <span class="hljs-number">0</span>) {
|
|
<span class="hljs-keyword">const</span> newOption = requestDetail.requestOptions;
|
|
newOption.port = <span class="hljs-number">443</span>;
|
|
<span class="hljs-keyword">return</span> {
|
|
protocol: <span class="hljs-string">'https'</span>,
|
|
requestOptions: newOption
|
|
};
|
|
}
|
|
}
|
|
};
|
|
</code></pre>
|
|
<h3 id="修改返回状态码">修改返回状态码</h3>
|
|
<ul>
|
|
<li>把 所有<a href="http://httpbin.org" target="_blank">http://httpbin.org</a> 的返回状态码都改成404</li>
|
|
</ul>
|
|
<pre><code class="lang-bash">anyproxy --rule rule_sample/sample_modify_response_statuscode.js
|
|
</code></pre>
|
|
<pre><code class="lang-js"><span class="hljs-comment">/*
|
|
sample:
|
|
modify all status code of http://httpbin.org/ to 404
|
|
test:
|
|
curl -I 'http://httpbin.org/user-agent' --proxy http://127.0.0.1:8001
|
|
expected response:
|
|
HTTP/1.1 404 Not Found
|
|
*/</span>
|
|
<span class="hljs-built_in">module</span>.exports = {
|
|
*beforeSendResponse(requestDetail, responseDetail) {
|
|
<span class="hljs-keyword">if</span> (requestDetail.url.indexOf(<span class="hljs-string">'http://httpbin.org'</span>) === <span class="hljs-number">0</span>) {
|
|
<span class="hljs-keyword">const</span> newResponse = responseDetail.response;
|
|
newResponse.statusCode = <span class="hljs-number">404</span>;
|
|
<span class="hljs-keyword">return</span> {
|
|
response: newResponse
|
|
};
|
|
}
|
|
}
|
|
};
|
|
</code></pre>
|
|
<h3 id="修改返回头">修改返回头</h3>
|
|
<ul>
|
|
<li>在 <a href="http://httpbin.org/user-agent" target="_blank">http://httpbin.org/user-agent</a> 的返回头里加上 X-Proxy-By:AnyProxy</li>
|
|
</ul>
|
|
<pre><code class="lang-bash">anyproxy --rule rule_sample/sample_modify_response_header.js
|
|
</code></pre>
|
|
<pre><code class="lang-js"><span class="hljs-comment">/*
|
|
sample:
|
|
modify response header of http://httpbin.org/user-agent
|
|
test:
|
|
curl -I 'http://httpbin.org/user-agent' --proxy http://127.0.0.1:8001
|
|
expected response:
|
|
X-Proxy-By: AnyProxy
|
|
*/</span>
|
|
<span class="hljs-built_in">module</span>.exports = {
|
|
*beforeSendResponse(requestDetail, responseDetail) {
|
|
<span class="hljs-keyword">if</span> (requestDetail.url.indexOf(<span class="hljs-string">'http://httpbin.org/user-agent'</span>) === <span class="hljs-number">0</span>) {
|
|
<span class="hljs-keyword">const</span> newResponse = responseDetail.response;
|
|
newResponse.header[<span class="hljs-string">'X-Proxy-By'</span>] = <span class="hljs-string">'AnyProxy'</span>;
|
|
<span class="hljs-keyword">return</span> {
|
|
response: newResponse
|
|
};
|
|
}
|
|
}
|
|
};
|
|
</code></pre>
|
|
<h3 id="修改返回内容并延迟">修改返回内容并延迟</h3>
|
|
<ul>
|
|
<li>在 <a href="http://httpbin.org/user-agent" target="_blank">http://httpbin.org/user-agent</a> 的返回最后追加AnyProxy的签名,并延迟5秒</li>
|
|
</ul>
|
|
<pre><code class="lang-bash">anyproxy --rule rule_sample/sample_modify_response_data.js
|
|
</code></pre>
|
|
<pre><code class="lang-js"><span class="hljs-comment">/*
|
|
sample:
|
|
modify response data of http://httpbin.org/user-agent
|
|
test:
|
|
curl 'http://httpbin.org/user-agent' --proxy http://127.0.0.1:8001
|
|
expected response:
|
|
{ "user-agent": "curl/7.43.0" } -- AnyProxy Hacked! --
|
|
*/</span>
|
|
|
|
<span class="hljs-built_in">module</span>.exports = {
|
|
*beforeSendResponse(requestDetail, responseDetail) {
|
|
<span class="hljs-keyword">if</span> (requestDetail.url === <span class="hljs-string">'http://httpbin.org/user-agent'</span>) {
|
|
<span class="hljs-keyword">const</span> newResponse = responseDetail.response;
|
|
newResponse.body += <span class="hljs-string">'-- AnyProxy Hacked! --'</span>;
|
|
<span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Promise</span>((resolve, reject) => {
|
|
setTimeout(() => { <span class="hljs-comment">// delay the response for 5s</span>
|
|
resolve({ response: newResponse });
|
|
}, <span class="hljs-number">5000</span>);
|
|
});
|
|
}
|
|
},
|
|
};
|
|
</code></pre>
|
|
<h1 id="证书配置">证书配置</h1>
|
|
<h3 id="osx系统信任ca证书">OSX系统信任CA证书</h3>
|
|
<ul>
|
|
<li>类似这种报错都是因为系统没有信任AnyProxy生成的CA所造成的</li>
|
|
</ul>
|
|
<p><img src="https://zos.alipayobjects.com/rmsportal/CBkLGYgvoHAYwNVAYkpk.png" width="450"></p>
|
|
<blockquote>
|
|
<p>警告:CA证书和系统安全息息相关,建议亲自生成,并妥善保管</p>
|
|
</blockquote>
|
|
<p>安装CA:</p>
|
|
<ul>
|
|
<li><p>双击打开<em>rootCA.crt</em></p>
|
|
</li>
|
|
<li><p>确认将证书添加到login或system</p>
|
|
</li>
|
|
</ul>
|
|
<p><img src="https://zos.alipayobjects.com/rmsportal/bCwNUFFpvsmVuljQKrIk.png" width="350"></p>
|
|
<ul>
|
|
<li>找到刚刚导入的AnyProxy证书,配置为信任(Always Trust)</li>
|
|
</ul>
|
|
<p><img src="https://zos.alipayobjects.com/rmsportal/HOmEElNGdoZEWFMLsTNT.png" width="700"></p>
|
|
<h3 id="windows系统信任ca证书">Windows系统信任CA证书</h3>
|
|
<p><img src="https://t.alipayobjects.com/tfscom/T1D3hfXeFtXXXXXXXX.jpg" width="700"></p>
|
|
<h3 id="配置osx系统代理">配置OSX系统代理</h3>
|
|
<ul>
|
|
<li>在wifi高级设置中,配置http代理即可</li>
|
|
</ul>
|
|
<p><img src="https://zos.alipayobjects.com/rmsportal/vduwhobSTypTfgniBvoa.png" width="500"></p>
|
|
<h3 id="配置浏览器http代理">配置浏览器HTTP代理</h3>
|
|
<ul>
|
|
<li>以Chrome的<a href="https://chrome.google.com/webstore/detail/padekgcemlokbadohgkifijomclgjgif" target="_blank">SwitchyOmega插件</a>为例</li>
|
|
</ul>
|
|
<p><img src="https://zos.alipayobjects.com/rmsportal/jIPZrKmqXRaSledQeJUJ.png" width="500"></p>
|
|
<h3 id="ios系统信任ca证书">iOS系统信任CA证书</h3>
|
|
<ul>
|
|
<li>点击web ui中的 <em>Root CA</em>,按提示扫描二维码即可安装</li>
|
|
</ul>
|
|
<p><img src="https://zos.alipayobjects.com/rmsportal/BrugmMelGVysLDOIBblj.png" width="260"></p>
|
|
<h3 id="ios--103信任ca证书">iOS >= 10.3信任CA证书</h3>
|
|
<ul>
|
|
<li>除了上述证书安装过程,还需要在 <em>设置->通用->关于本机->证书信任设置</em> 中把AnyProxy证书的开关打开,否则safari将报错。</li>
|
|
</ul>
|
|
<p><img src="https://zos.alipayobjects.com/rmsportal/hVWkXHrzHmOKOtCKGUWx.png" width="500"></p>
|
|
<h3 id="配置iosandroid系统代理">配置iOS/Android系统代理</h3>
|
|
<ul>
|
|
<li><p>代理服务器都在wifi设置中配置</p>
|
|
</li>
|
|
<li><p>iOS HTTP代理配置</p>
|
|
</li>
|
|
</ul>
|
|
<p><img src="https://zos.alipayobjects.com/rmsportal/tLGqIozhffTccUgPakuw.png" width="260"></p>
|
|
<ul>
|
|
<li>Android HTTP代理配置</li>
|
|
</ul>
|
|
<p><img src="https://zos.alipayobjects.com/rmsportal/YQtbQYVNuOszZGdAOauU.png" width="260"></p>
|
|
<h1 id="faq">FAQ</h1>
|
|
<h4 id="q-为什么https请求不能进入处理函数?">Q: 为什么https请求不能进入处理函数?</h4>
|
|
<p> A: 以下任意一项都能用来改变https的处理特性:</p>
|
|
<pre><code> 1. 命令行启动AnyProxy时配置`--intercept`参数,按npm模块启动时配置`forceProxyHttps`参数,所有Https请求都会被替换证书并解析
|
|
2. 规则文件内提供`beforeDealHttpsRequest`方法,返回 *true* 的https请求会被解析
|
|
</code></pre><h4 id="q-提示-function-is-not-yieldable">Q: 提示 <em>function is not yieldable</em></h4>
|
|
<ul>
|
|
<li>A: 规则模块是用 <a href="https://www.npmjs.com/package/co" target="_blank">co</a> 驱动的,函数需要满足yieldable。可以使用generator方法或是返回Promise。</li>
|
|
</ul>
|
|
<h4 id="q-the-connection-is-not-private">Q: The connection is not private</h4>
|
|
<p>当访问特定的HTTPS站点,AnyProxy会提示该站点不是一个安全的网站,这通常是因为站点的证书设置不能被正确识别导致的(比如,站点的证书是自签发的)。如果您信任该网站,可以用以下方式来继续访问:</p>
|
|
<ul>
|
|
<li><p>命令行直接启动</p>
|
|
<p>通过启动参数 <code>--ignore-unauthorized-ssl</code> 来忽略证书认证的错误。需要注意的是,该参数是全局生效的,如果你在此期间访问了其他未知的网站,他们的证书问题也会被忽略,这可能会带来安全隐患。</p>
|
|
<pre><code class="lang-bash">anyproxy -i --ignore-unauthorized-ssl
|
|
</code></pre>
|
|
</li>
|
|
<li><p>在Nodejs代码中启动</p>
|
|
<p>在构造AnyProxy实例的时候,传入参数<code>dangerouslyIgnoreUnauthorized:true</code>, 如下:</p>
|
|
<pre><code class="lang-js"> <span class="hljs-keyword">const</span> options = {
|
|
...,
|
|
dangerouslyIgnoreUnauthorized: <span class="hljs-literal">true</span>
|
|
};
|
|
|
|
<span class="hljs-keyword">const</span> anyproxyIns = <span class="hljs-keyword">new</span> AnyProxy.ProxyCore(options);
|
|
anyproxyIns.start();
|
|
</code></pre>
|
|
<p><em>通过这种方式初始化的AnyProxy,其配置也是全局性的,所有网站的证书问题都会被忽略</em></p>
|
|
</li>
|
|
<li><p>通过自定义的Rule来修改</p>
|
|
<p>我们自然也可以借助自定义的Rule来实现这个效果,而且我们还可以控制到只允许指定网址的证书错误,对不在列表的网址,进行证书的强验证。</p>
|
|
<pre><code class="lang-js"><span class="hljs-built_in">module</span>.exports = {
|
|
*beforeSendRequest(requestDetail) {
|
|
<span class="hljs-keyword">if</span> (requestDetail.url.indexOf(<span class="hljs-string">'https://the-site-you-know.com'</span>) === <span class="hljs-number">0</span>) {
|
|
<span class="hljs-keyword">const</span> newRequestOptions = requestDetail.requestOptions;
|
|
<span class="hljs-comment">// 设置属性 rejectUnauthorized 为 false</span>
|
|
newRequestOptions.rejectUnauthorized = <span class="hljs-literal">false</span>;
|
|
<span class="hljs-keyword">return</span> {
|
|
requestOptions: newRequestOptions
|
|
};
|
|
}
|
|
},
|
|
};
|
|
</code></pre>
|
|
</li>
|
|
</ul>
|
|
|
|
|
|
</section>
|
|
|
|
</div>
|
|
<div class="search-results">
|
|
<div class="has-results">
|
|
|
|
<h1 class="search-results-title"><span class='search-results-count'></span> results matching "<span class='search-query'></span>"</h1>
|
|
<ul class="search-results-list"></ul>
|
|
|
|
</div>
|
|
<div class="no-results">
|
|
|
|
<h1 class="search-results-title">No results matching "<span class='search-query'></span>"</h1>
|
|
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<a href="./#快速开始" class="navigation navigation-next navigation-unique" aria-label="Next page: 快速开始">
|
|
<i class="fa fa-angle-right"></i>
|
|
</a>
|
|
|
|
|
|
|
|
</div>
|
|
|
|
<script>
|
|
var gitbook = gitbook || [];
|
|
gitbook.push(function() {
|
|
gitbook.page.hasChanged({"page":{"title":"简介","level":"1.1","depth":1,"next":{"title":"快速开始","level":"1.2","depth":1,"anchor":"#快速开始","path":"README.md","ref":"README.md#快速开始","articles":[{"title":"安装","level":"1.2.1","depth":2,"anchor":"#安装","path":"README.md","ref":"README.md#安装","articles":[]},{"title":"启动","level":"1.2.2","depth":2,"anchor":"#启动","path":"README.md","ref":"README.md#启动","articles":[]},{"title":"其他命令","level":"1.2.3","depth":2,"anchor":"#其他命令","path":"README.md","ref":"README.md#其他命令","articles":[]},{"title":"作为npm模块启动","level":"1.2.4","depth":2,"anchor":"#作为npm模块使用","path":"README.md","ref":"README.md#作为npm模块使用","articles":[]}]},"dir":"ltr"},"config":{"plugins":[],"styles":{"website":"styles/website.css","pdf":"styles/pdf.css","epub":"styles/epub.css","mobi":"styles/mobi.css","ebook":"styles/ebook.css","print":"styles/print.css"},"pluginsConfig":{"livereload":{},"highlight":{},"search":{},"lunr":{"maxIndexSize":1000000,"ignoreSpecialCharacters":false},"sharing":{"facebook":true,"twitter":true,"google":false,"weibo":false,"instapaper":false,"vk":false,"all":["facebook","google","twitter","weibo","instapaper"]},"fontsettings":{"theme":"white","family":"sans","size":2},"theme-default":{"styles":{"website":"styles/website.css","pdf":"styles/pdf.css","epub":"styles/epub.css","mobi":"styles/mobi.css","ebook":"styles/ebook.css","print":"styles/print.css"},"showLevel":false}},"theme":"default","author":"AnyProxy","pdf":{"pageNumbers":true,"fontSize":12,"fontFamily":"Arial","paperSize":"a4","chapterMark":"pagebreak","pageBreaksBefore":"/","margin":{"right":62,"left":62,"top":56,"bottom":56}},"structure":{"langs":"LANGS.md","readme":"README.md","glossary":"GLOSSARY.md","summary":"SUMMARY.md"},"variables":{},"title":"AnyProxy","language":"cn","gitbook":"*","description":"A fully configurable http/https proxy in NodeJS"},"file":{"path":"README.md","mtime":"2017-12-01T13:58:00.991Z","type":"markdown"},"gitbook":{"version":"3.2.2","time":"2017-12-01T13:58:02.250Z"},"basePath":".","book":{"language":"cn"}});
|
|
});
|
|
</script>
|
|
</div>
|
|
|
|
|
|
<script src="../gitbook/gitbook.js"></script>
|
|
<script src="../gitbook/theme.js"></script>
|
|
|
|
|
|
<script src="../gitbook/gitbook-plugin-livereload/plugin.js"></script>
|
|
|
|
|
|
|
|
<script src="../gitbook/gitbook-plugin-search/search-engine.js"></script>
|
|
|
|
|
|
|
|
<script src="../gitbook/gitbook-plugin-search/search.js"></script>
|
|
|
|
|
|
|
|
<script src="../gitbook/gitbook-plugin-lunr/lunr.min.js"></script>
|
|
|
|
|
|
|
|
<script src="../gitbook/gitbook-plugin-lunr/search-lunr.js"></script>
|
|
|
|
|
|
|
|
<script src="../gitbook/gitbook-plugin-sharing/buttons.js"></script>
|
|
|
|
|
|
|
|
<script src="../gitbook/gitbook-plugin-fontsettings/fontsettings.js"></script>
|
|
|
|
|
|
|
|
</body>
|
|
</html>
|
|
|