anyproxy/4.x/cn.html
2017-04-05 16:22:17 +08:00

825 lines
48 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, minimal-ui">
<title>AnyProxy</title>
<link type="text/css" rel="stylesheet" href="assets/css/github-markdown.css">
<link type="text/css" rel="stylesheet" href="assets/css/pilcrow.css">
<link type="text/css" rel="stylesheet" href="assets/css/atom-one-light.css" />
<link type="text/css" rel="stylesheet" href="assets/css/custom.css" />
<meta name="description" content="A fully configurable proxy in NodeJS, which can handle HTTPS requests perfectly.">
<meta name="description" content="AnyProxy - 开放式的HTTP/HTTPS代理你可以灵活控制各种网络数据">
<meta name="keywords" content="代理服务器 Proxy HTTP HTTPS">
<script>
//redirect to Chinese version if in China
if (new Date().getTimezoneOffset() == "-480" && !(/(cn|en)/i.test(location.href))) {
location.href = "./cn.html";
} else {
var _hmt = _hmt || []; (function () { var hm = document.createElement("script"); hm.src = "//hm.baidu.com/hm.js?4e51565b7d471fd6623c163a8fd79e07"; var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(hm, s); })();
}
</script>
</head>
<body>
<a href="https://github.com/alibaba/anyproxy/tree/4.x" target="_blank">
<img style="position: fixed; top: 0; right: 0; border: 0;z-index: 1;" src="https://camo.githubusercontent.com/a6677b08c955af8400f44c6298f40e7d19cc5b2d/68747470733a2f2f73332e616d617a6f6e6177732e636f6d2f6769746875622f726962626f6e732f666f726b6d655f72696768745f677261795f3664366436642e706e67"
alt="Fork me on GitHub" data-canonical-src="https://s3.amazonaws.com/github/ribbons/forkme_right_gray_6d6d6d.png">
</a>
<article class="markdown-body">
<div class="toc-container" id="j_toc">
<div class="toc-content"><ul class="nav nav-list">
<li class="sidebar-header-1"><a href="#anyproxy">AnyProxy</a></li>
<li class="sidebar-header-2"><a href="#快速上手">快速上手</a></li>
<li class="sidebar-header-3"><a href="#安装">安装</a></li>
<li class="sidebar-header-3"><a href="#启动">启动</a></li>
<li class="sidebar-header-3"><a href="#其他命令">其他命令</a></li>
<li class="sidebar-header-2"><a href="#代理https请求">代理https请求</a></li>
<li class="sidebar-header-2"><a href="#规则模块rule">规则模块Rule</a></li>
<li class="sidebar-header-3"><a href="#开发示例">开发示例</a></li>
<li class="sidebar-header-3"><a href="#处理流程">处理流程</a></li>
<li class="sidebar-header-3"><a href="#如何引用">如何引用</a></li>
<li class="sidebar-header-2"><a href="#规则接口文档">规则接口文档</a></li>
<li class="sidebar-header-3"><a href="#summary">summary</a></li>
<li class="sidebar-header-4"><a href="#summary-1">summary</a></li>
<li class="sidebar-header-3"><a href="#beforesendrequest">beforeSendRequest</a></li>
<li class="sidebar-header-4"><a href="#beforesendrequest(requestdetail)">beforeSendRequest(requestDetail)</a></li>
<li class="sidebar-header-3"><a href="#beforesendresponse">beforeSendResponse</a></li>
<li class="sidebar-header-4"><a href="#beforesendresponse(requestdetail,-responsedetail)">beforeSendResponse(requestDetail, responseDetail)</a></li>
<li class="sidebar-header-3"><a href="#beforedealhttpsrequest">beforeDealHttpsRequest</a></li>
<li class="sidebar-header-4"><a href="#beforedealhttpsrequest(requestdetail)">beforeDealHttpsRequest(requestDetail)</a></li>
<li class="sidebar-header-3"><a href="#onerror">onError</a></li>
<li class="sidebar-header-4"><a href="#onerror(requestdetail,-error)">onError(requestDetail, error)</a></li>
<li class="sidebar-header-3"><a href="#onconnecterror">onConnectError</a></li>
<li class="sidebar-header-4"><a href="#onconnecterror(requestdetail,-error)">onConnectError(requestDetail, error)</a></li>
<li class="sidebar-header-3"><a href="#faq">FAQ</a></li>
<li class="sidebar-header-2"><a href="#规则模块样例">规则模块样例</a></li>
<li class="sidebar-header-3"><a href="#使用本地数据">使用本地数据</a></li>
<li class="sidebar-header-3"><a href="#修改请求头">修改请求头</a></li>
<li class="sidebar-header-3"><a href="#修改请求数据">修改请求数据</a></li>
<li class="sidebar-header-3"><a href="#修改请求的目标地址">修改请求的目标地址</a></li>
<li class="sidebar-header-3"><a href="#修改请求协议">修改请求协议</a></li>
<li class="sidebar-header-3"><a href="#修改返回状态码">修改返回状态码</a></li>
<li class="sidebar-header-3"><a href="#修改返回头">修改返回头</a></li>
<li class="sidebar-header-3"><a href="#修改返回内容并延迟">修改返回内容并延迟</a></li>
<li class="sidebar-header-2"><a href="#作为npm模块使用">作为npm模块使用</a></li>
<li class="sidebar-header-2"><a href="#关于anyproxy">关于AnyProxy</a></li>
<li class="sidebar-header-2"><a href="#配置帮助">配置帮助</a></li>
<li class="sidebar-header-3"><a href="#osx系统信任ca证书">OSX系统信任CA证书</a></li>
<li class="sidebar-header-3"><a href="#windows系统信任ca证书">Windows系统信任CA证书</a></li>
<li class="sidebar-header-3"><a href="#配置osx系统代理">配置OSX系统代理</a></li>
<li class="sidebar-header-3"><a href="#配置浏览器http代理">配置浏览器HTTP代理</a></li>
<li class="sidebar-header-3"><a href="#配置ios/android系统代理">配置iOS/Android系统代理</a></li>
</ul>
</div>
</div>
<div class="main-content"><h1 id="anyproxy"><a class="header-link" href="#anyproxy"></a>AnyProxy</h1>
<blockquote>
<p>本文档的适用范围是AnyProxy 4.0此版本当前正在beta中欢迎提供反馈</p>
</blockquote>
<p>Ref: <a href="./en.html">English Doc</a></p>
<p>AnyProxy是一个开放式的HTTP代理服务器。</p>
<p>Github主页<a href="https://github.com/alibaba/anyproxy/tree/4.x">https://github.com/alibaba/anyproxy/tree/4.x</a></p>
<p>主要特性包括:</p>
<ul class="list">
<li>基于Node.js开放二次开发能力允许自定义请求处理逻辑</li>
<li>支持Https的解析</li>
<li>提供GUI界面用以观察请求</li>
</ul>
<p>相比3.x版本AnyProxy 4.0的主要变化:</p>
<ul class="list">
<li>规则文件Rule全面支持Promise和Generator</li>
<li>简化了规则文件内的接口</li>
<li>Web版界面重构</li>
</ul>
<p class="img-container"><img src="https://zos.alipayobjects.com/rmsportal/SqVntpzmscXPbSzfcGcr.png" width="500" /></p>
<h2 id="快速上手"><a class="header-link" href="#快速上手"></a>快速上手</h2>
<h3 id="安装"><a class="header-link" href="#安装"></a>安装</h3>
<pre class="hljs"><code>npm install -g anyproxy@beta <span class="hljs-comment">#本文档对应的AnyProxy为4.0Beta版</span></code></pre><h3 id="启动"><a class="header-link" href="#启动"></a>启动</h3>
<ul class="list">
<li>命令行启动AnyProxy默认端口号8001</li>
</ul>
<pre class="hljs"><code>anyproxy</code></pre><ul class="list">
<li>启动后将终端http代理服务器配置为127.0.0.1:8001即可</li>
<li>访问<a href="http://127.0.0.1:8002">http://127.0.0.1:8002</a> web界面上能看到所有的请求信息</li>
</ul>
<h3 id="其他命令"><a class="header-link" href="#其他命令"></a>其他命令</h3>
<ul class="list">
<li>配置启动端口如1080端口启动</li>
</ul>
<pre class="hljs"><code>anyproxy --port 1080</code></pre><h2 id="代理https请求"><a class="header-link" href="#代理https请求"></a>代理https请求</h2>
<ul class="list">
<li>AnyProxy默认不对https请求做处理如需看到明文信息需要配置CA证书</li>
</ul>
<blockquote>
<p>解析https请求的原理是中间人攻击man-in-the-middle用户必须信任AnyProxy生成的CA证书才能进行后续流程</p>
</blockquote>
<ul class="list">
<li>生成证书并解析所有https请求</li>
</ul>
<pre class="hljs"><code>anyproxy-ca <span class="hljs-comment">#生成rootCA证书生成后需要手动信任</span>
anyproxy --intercept <span class="hljs-comment">#启动AnyProxy并解析所有https请求</span></code></pre><ul class="list">
<li><a href="#osx系统信任ca证书">附录如何信任CA证书</a></li>
</ul>
<h2 id="规则模块rule"><a class="header-link" href="#规则模块rule"></a>规则模块Rule</h2>
<p>AnyProxy提供了二次开发的能力你可以用js编写自己的规则模块rule来自定义网络请求的处理逻辑。</p>
<blockquote>
<p>注意:引用规则前,请务必确保文件来源可靠,以免发生安全问题</p>
</blockquote>
<p>规则模块的能力范围包括:</p>
<ul class="list">
<li>拦截并修改正在发送的请求<ul class="list">
<li>可修改内容包括请求头request header)请求体request body甚至是请求的目标地址等</li>
</ul>
</li>
<li>拦截并修改服务端响应<ul class="list">
<li>可修改的内容包括http状态码(status code)、响应头response header、响应内容等</li>
</ul>
</li>
<li>拦截https请求对内容做修改<ul class="list">
<li>本质是中间人攻击man-in-the-middle attack需要客户端提前信任AnyProxy生成的CA</li>
</ul>
</li>
</ul>
<h3 id="开发示例"><a class="header-link" href="#开发示例"></a>开发示例</h3>
<ul class="list">
<li><p>举例</p>
<ul class="list">
<li>需要编写一个规则模块,在 GET <a href="http://httpbin.org/user-agent">http://httpbin.org/user-agent</a> 的返回值里加上测试信息并延迟5秒返回</li>
</ul>
</li>
<li><p>Step 1编写规则</p>
<pre class="hljs"><code><span class="hljs-comment">// file: sample.js</span>
<span class="hljs-built_in">module</span>.exports = {
<span class="hljs-attr">summary</span>: <span class="hljs-string">'a rule to modify 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>(<span class="hljs-function">(<span class="hljs-params">resolve, reject</span>) =&gt;</span> {
setTimeout(<span class="hljs-function"><span class="hljs-params">()</span> =&gt;</span> { <span class="hljs-comment">// delay</span>
resolve({ <span class="hljs-attr">response</span>: newResponse });
}, <span class="hljs-number">5000</span>);
});
}
},
};</code></pre></li>
<li><p>Step 2, 启动AnyProxy加载规则</p>
<ul class="list">
<li>运行 <code>anyproxy --rule sample.js</code></li>
</ul>
</li>
<li><p>Step 3, 测试规则</p>
<ul class="list">
<li><p>用curl测试 </p>
<pre class="hljs"><code>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">http://httpbin.org/user-agent</a> </p>
</li>
<li><p>经过代理服务器后,期望的返回如下</p>
</li>
</ul>
<pre class="hljs"><code>{
<span class="hljs-string">"user-agent"</span>: <span class="hljs-string">"curl/7.43.0"</span>
}
- AnyProxy Hacked!</code></pre></li>
<li><p>Step 4, 查看请求信息</p>
<ul class="list">
<li>浏览器访问<a href="http://127.0.0.1:8002">http://127.0.0.1:8002</a> ,界面上能看到刚才的请求信息</li>
</ul>
</li>
</ul>
<h3 id="处理流程"><a class="header-link" href="#处理流程"></a>处理流程</h3>
<ul class="list">
<li>处理流程图如下</li>
</ul>
<p class="img-container"><img src="https://zos.alipayobjects.com/rmsportal/TWyNuSJtEZBdrdcOMRjE.png" width="550" /></p>
<ul class="list">
<li><p>当http请求经过代理服务器时具体处理过程是</p>
<ul class="list">
<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 class="list">
<li>调用规则模块<code>beforeDealHttpsRequest</code>方法,如果返回<code>true</code>,会明文解析这个请求,其他请求不处理</li>
<li>被明文解析后的https请求处理流程同http一致。未明文解析请求不会再进入规则模块做处理。</li>
</ul>
</li>
</ul>
<h3 id="如何引用"><a class="header-link" href="#如何引用"></a>如何引用</h3>
<p>如下几种方案都可以用来引用规则模块:</p>
<ul class="list">
<li>使用本地路径<pre class="hljs"><code>anyproxy --rule ./rule.js</code></pre></li>
<li><p>使用在线地址</p>
<pre class="hljs"><code>anyproxy --rule https://sample.com/rule.js</code></pre></li>
<li><p>使用npm包</p>
<ul class="list">
<li>AnyProxy使用<code>require()</code>加载本地规则你可以在参数里传入一个本地的npm包路径或是某个全局安装的npm包</li>
</ul>
<pre class="hljs"><code>anyproxy --rule ./myRulePkg/ <span class="hljs-comment">#本地包</span>
npm i -g myRulePkg &amp;&amp; anyproxy --rule myRulePkg <span class="hljs-comment">#全局包</span></code></pre></li>
</ul>
<h2 id="规则接口文档"><a class="header-link" href="#规则接口文档"></a>规则接口文档</h2>
<p>规则模块应该符合cmd规范一个典型的规则模块代码结构如下。模块中所有方法都是可选的只需实现业务感兴趣的部分即可。</p>
<pre class="hljs"><code><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">co</a> 驱动的函数需要满足yieldable。可以返回promise或使用generator函数。</p>
</blockquote>
<h3 id="summary"><a class="header-link" href="#summary"></a>summary</h3>
<h4 id="summary-1"><a class="header-link" href="#summary-1"></a>summary</h4>
<ul class="list">
<li>规则模块的介绍文案用于AnyProxy提示用户</li>
</ul>
<h3 id="beforesendrequest"><a class="header-link" href="#beforesendrequest"></a>beforeSendRequest</h3>
<h4 id="beforesendrequest(requestdetail)"><a class="header-link" href="#beforesendrequest(requestdetail)"></a>beforeSendRequest(requestDetail)</h4>
<ul class="list">
<li>AnyProxy向服务端发送请求前会调用<code>beforeSendRequest</code>,并带上参数<code>requestDetail</code></li>
<li><code>requestDetail</code> <ul class="list">
<li><code>protocol</code> {string} 请求使用的协议http或者https</li>
<li><code>requestOptions</code> {object} 即将发送的请求配置供require(&#39;http&#39;).request作为使用。详见<a href="https://nodejs.org/api/http.html#http_http_request_options_callback">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 class="hljs"><code>{
<span class="hljs-attr">protocol</span>: <span class="hljs-string">'http'</span>,
<span class="hljs-attr">url</span>: <span class="hljs-string">'http://anyproxy.io/'</span>,
<span class="hljs-attr">requestOptions</span>: {
<span class="hljs-attr">hostname</span>: <span class="hljs-string">'anyproxy.io'</span>,
<span class="hljs-attr">port</span>: <span class="hljs-number">80</span>,
<span class="hljs-attr">path</span>: <span class="hljs-string">'/'</span>,
<span class="hljs-attr">method</span>: <span class="hljs-string">'GET'</span>,
<span class="hljs-attr">headers</span>: {
<span class="hljs-attr">Host</span>: <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>
}
},
<span class="hljs-attr">requestData</span>: <span class="hljs-string">'...'</span>,
<span class="hljs-attr">_req</span>: { <span class="hljs-comment">/* ... */</span>}
}</code></pre></li>
<li><p>以下几种返回都是合法的</p>
<ul class="list">
<li>不做任何处理返回null</li>
</ul>
<pre class="hljs"><code><span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>;</code></pre><ul class="list">
<li>修改请求协议如强制改用https发起请求</li>
</ul>
<pre class="hljs"><code><span class="hljs-keyword">return</span> {
<span class="hljs-attr">protocol</span>: <span class="hljs-string">'https'</span>
};</code></pre><ul class="list">
<li>修改请求参数</li>
</ul>
<pre class="hljs"><code><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> {
<span class="hljs-attr">requestOptions</span>: newOption
};</code></pre><ul class="list">
<li>修改请求body</li>
</ul>
<pre class="hljs"><code><span class="hljs-keyword">return</span> {
<span class="hljs-attr">requestData</span>: <span class="hljs-string">'my new request data'</span>
<span class="hljs-comment">//这里也可以同时加上requestOptions</span>
};</code></pre><ul class="list">
<li>直接返回客户端,不再发起请求,其中<code>statusCode</code> <code>header</code> 是必选字段</li>
</ul>
<pre class="hljs"><code><span class="hljs-keyword">return</span> {
<span class="hljs-attr">response</span>: {
<span class="hljs-attr">statusCode</span>: <span class="hljs-number">200</span>,
<span class="hljs-attr">header</span>: { <span class="hljs-string">'content-type'</span>: <span class="hljs-string">'text/html'</span> },
<span class="hljs-attr">body</span>: <span class="hljs-string">'this could be a &lt;string&gt; or &lt;buffer&gt;'</span>
}
};</code></pre></li>
</ul>
<h3 id="beforesendresponse"><a class="header-link" href="#beforesendresponse"></a>beforeSendResponse</h3>
<h4 id="beforesendresponse(requestdetail,-responsedetail)"><a class="header-link" href="#beforesendresponse(requestdetail,-responsedetail)"></a>beforeSendResponse(requestDetail, responseDetail)</h4>
<ul class="list">
<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 class="list">
<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 class="hljs"><code>{
<span class="hljs-attr">response</span>: {
<span class="hljs-attr">statusCode</span>: <span class="hljs-number">200</span>,
<span class="hljs-attr">header</span>: {
<span class="hljs-string">'Content-Type'</span>: <span class="hljs-string">'image/gif'</span>,
<span class="hljs-attr">Connection</span>: <span class="hljs-string">'close'</span>,
<span class="hljs-string">'Cache-Control'</span>: <span class="hljs-string">'...'</span>
},
<span class="hljs-attr">body</span>: <span class="hljs-string">'...'</span>
},
<span class="hljs-attr">_res</span>: { <span class="hljs-comment">/* ... */</span> }
}</code></pre></li>
<li><p>以下几种返回都是合法的</p>
<ul class="list">
<li>不做任何处理返回null</li>
</ul>
<pre class="hljs"><code><span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>;</code></pre><ul class="list">
<li>修改返回的状态码</li>
</ul>
<pre class="hljs"><code><span class="hljs-keyword">var</span> newResponse = <span class="hljs-built_in">Object</span>.assign({}, responseDetail.reponse);
newResponse.statusCode = <span class="hljs-number">404</span>;
<span class="hljs-keyword">return</span> {
<span class="hljs-attr">response</span>: newResponse
};</code></pre><ul class="list">
<li>修改返回的内容</li>
</ul>
<pre class="hljs"><code><span class="hljs-keyword">var</span> newResponse = <span class="hljs-built_in">Object</span>.assign({}, responseDetail.reponse);
newResponse.body += <span class="hljs-string">'--from anyproxy--'</span>;
<span class="hljs-keyword">return</span> {
<span class="hljs-attr">response</span>: newResponse
};</code></pre></li>
</ul>
<h3 id="beforedealhttpsrequest"><a class="header-link" href="#beforedealhttpsrequest"></a>beforeDealHttpsRequest</h3>
<h4 id="beforedealhttpsrequest(requestdetail)"><a class="header-link" href="#beforedealhttpsrequest(requestdetail)"></a>beforeDealHttpsRequest(requestDetail)</h4>
<ul class="list">
<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 class="list">
<li><code>host</code> {string} 请求目标的Host受制于协议这里无法获取完整url</li>
<li><code>_req</code> {object} 请求的原始request</li>
</ul>
</li>
<li>返回值<ul class="list">
<li><code>true</code>或者<code>false</code>表示是否需要AnyProxy替换证书并解析https</li>
</ul>
</li>
</ul>
<h3 id="onerror"><a class="header-link" href="#onerror"></a>onError</h3>
<h4 id="onerror(requestdetail,-error)"><a class="header-link" href="#onerror(requestdetail,-error)"></a>onError(requestDetail, error)</h4>
<ul class="list">
<li>在请求处理过程中发生错误时AnyProxy会调用<code>onError</code>方法,并提供对应的错误信息</li>
<li>多数场景下错误会在请求目标服务器的时候发生比如DNS解析失败、请求超时等</li>
<li><code>requestDetail</code><code>beforeSendRequest</code>中的参数</li>
<li><p>以下几种返回都是合法的</p>
<ul class="list">
<li>不做任何处理。此时AnyProxy会返回一个默认的错误页。</li>
</ul>
<pre class="hljs"><code><span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>;</code></pre><ul class="list">
<li>返回自定义错误页</li>
</ul>
<pre class="hljs"><code><span class="hljs-keyword">return</span> {
<span class="hljs-attr">response</span>: {
<span class="hljs-attr">statusCode</span>: <span class="hljs-number">200</span>,
<span class="hljs-attr">header</span>: { <span class="hljs-string">'content-type'</span>: <span class="hljs-string">'text/html'</span> },
<span class="hljs-attr">body</span>: <span class="hljs-string">'this could be a &lt;string&gt; or &lt;buffer&gt;'</span>
}
};</code></pre></li>
</ul>
<h3 id="onconnecterror"><a class="header-link" href="#onconnecterror"></a>onConnectError</h3>
<h4 id="onconnecterror(requestdetail,-error)"><a class="header-link" href="#onconnecterror(requestdetail,-error)"></a>onConnectError(requestDetail, error)</h4>
<ul class="list">
<li>AnyProxy在与目标HTTPS服务器建立连接的过程中如果发生错误AnyProxy会调用这个方法</li>
<li><code>requestDetail</code><code>beforeDealHttpsRequest</code>中的参数</li>
<li>此处无法控制向客户端的返回信息,无需返回值。</li>
</ul>
<h3 id="faq"><a class="header-link" href="#faq"></a>FAQ</h3>
<ul class="list">
<li>Q: 为什么https请求不能进入处理函数</li>
<li><p>A: 以下任意一项都能用来改变https的处理特性</p>
<ol class="list">
<li>命令行启动AnyProxy时配置<code>--intercept</code>参数按npm模块启动时配置<code>forceProxyHttps</code>参数所有Https请求都会被替换证书并解析</li>
<li>规则文件内提供<code>beforeDealHttpsRequest</code>方法,返回 <em>true</em> 的https请求会被解析</li>
</ol>
</li>
<li><p>Q: 提示 <em>function is not yieldable</em></p>
</li>
<li>A: 规则模块是用 <a href="https://www.npmjs.com/package/co">co</a> 驱动的函数需要满足yieldable。可以使用generator方法或是返回Promise。</li>
</ul>
<h2 id="规则模块样例"><a class="header-link" href="#规则模块样例"></a>规则模块样例</h2>
<ul class="list">
<li>这里提供一些样例,来讲解规则模块的常见用法</li>
<li>你可以通过 <code>anyproxy --rule http://....js</code> 来加载模块并体验</li>
<li>用curl发请求测试的方法如下<ul class="list">
<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="使用本地数据"><a class="header-link" href="#使用本地数据"></a>使用本地数据</h3>
<ul class="list">
<li>拦截发送到 <a href="http://httpbin.org">http://httpbin.org</a> 的请求,使用本地数据代替服务端返回</li>
</ul>
<pre class="hljs"><code>anyproxy --rule https://raw.githubusercontent.com/alibaba/anyproxy/4.x/rule_sample/sample_use_local_response.js</code></pre><pre class="hljs"><code><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 = {
<span class="hljs-attr">statusCode</span>: <span class="hljs-number">200</span>,
<span class="hljs-attr">header</span>: { <span class="hljs-string">'Content-Type'</span>: <span class="hljs-string">'application/json'</span> },
<span class="hljs-attr">body</span>: <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> {
<span class="hljs-attr">response</span>: localResponse
};
}
},
};</code></pre><h3 id="修改请求头"><a class="header-link" href="#修改请求头"></a>修改请求头</h3>
<ul class="list">
<li>修改发送到 httpbin.org 的user-agent</li>
</ul>
<pre class="hljs"><code>anyproxy --rule https://raw.githubusercontent.com/alibaba/anyproxy/4.x/rule_sample/sample_modify_request_header.js</code></pre><pre class="hljs"><code><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> {
<span class="hljs-attr">requestOptions</span>: newRequestOptions
};
}
},
};</code></pre><h3 id="修改请求数据"><a class="header-link" href="#修改请求数据"></a>修改请求数据</h3>
<ul class="list">
<li>修改发送到 <a href="http://httpbin.org/post">http://httpbin.org/post</a> 的post数据</li>
</ul>
<pre class="hljs"><code>anyproxy --rule https://raw.githubusercontent.com/alibaba/anyproxy/4.x/rule_sample/sample_modify_request_data.js</code></pre><pre class="hljs"><code><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 = {
*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> {
<span class="hljs-attr">requestData</span>: <span class="hljs-string">'i-am-anyproxy-modified-post-data'</span>
};
}
},
};</code></pre><h3 id="修改请求的目标地址"><a class="header-link" href="#修改请求的目标地址"></a>修改请求的目标地址</h3>
<ul class="list">
<li>把所有发送到 <a href="http://httpbin.org/">http://httpbin.org/</a> 的请求全部改到 <a href="http://httpbin.org/user-agent">http://httpbin.org/user-agent</a></li>
</ul>
<pre class="hljs"><code>anyproxy --rule https://raw.githubusercontent.com/alibaba/anyproxy/4.x/rule_sample/sample_modify_request_path.js</code></pre><pre class="hljs"><code><span class="hljs-comment">/*
sample:
redirect all httpbin.org requests to http://httpbin.org/user-agent
test:
curl http://httpbin.org/any-path --proxy http://127.0.0.1:8001
expected response:
{ "user-agent": "curl/7.43.0" }
*/</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.path = <span class="hljs-string">'/user-agent'</span>;
newRequestOptions.method = <span class="hljs-string">'GET'</span>;
<span class="hljs-keyword">return</span> {
<span class="hljs-attr">requestOptions</span>: newRequestOptions
};
}
},
};</code></pre><h3 id="修改请求协议"><a class="header-link" href="#修改请求协议"></a>修改请求协议</h3>
<ul class="list">
<li>把用http协议请求的 <a href="http://httpbin.org">http://httpbin.org</a> 改成https并发送</li>
</ul>
<pre class="hljs"><code>anyproxy --rule https://raw.githubusercontent.com/alibaba/anyproxy/4.x/rule_sample/sample_modify_request_protocol.js</code></pre><pre class="hljs"><code><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> {
<span class="hljs-attr">protocol</span>: <span class="hljs-string">'https'</span>,
<span class="hljs-attr">requestOptions</span>: newOption
};
}
}
};</code></pre><h3 id="修改返回状态码"><a class="header-link" href="#修改返回状态码"></a>修改返回状态码</h3>
<ul class="list">
<li>把 所有<a href="http://httpbin.org">http://httpbin.org</a> 的返回状态码都改成404</li>
</ul>
<pre class="hljs"><code>anyproxy --rule https://raw.githubusercontent.com/alibaba/anyproxy/4.x/rule_sample/sample_modify_response_statuscode.js</code></pre><pre class="hljs"><code><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> {
<span class="hljs-attr">response</span>: newResponse
};
}
}
};</code></pre><h3 id="修改返回头"><a class="header-link" href="#修改返回头"></a>修改返回头</h3>
<ul class="list">
<li><a href="http://httpbin.org/user-agent">http://httpbin.org/user-agent</a> 的返回头里加上 X-Proxy-By:AnyProxy</li>
</ul>
<pre class="hljs"><code>anyproxy --rule https://raw.githubusercontent.com/alibaba/anyproxy/4.x/rule_sample/sample_modify_response_header.js</code></pre><pre class="hljs"><code><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> {
<span class="hljs-attr">response</span>: newResponse
};
}
}
};</code></pre><h3 id="修改返回内容并延迟"><a class="header-link" href="#修改返回内容并延迟"></a>修改返回内容并延迟</h3>
<ul class="list">
<li><a href="http://httpbin.org/user-agent">http://httpbin.org/user-agent</a> 的返回最后追加AnyProxy的签名并延迟5秒</li>
</ul>
<pre class="hljs"><code>anyproxy --rule https://raw.githubusercontent.com/alibaba/anyproxy/4.x/rule_sample/sample_modify_response_data.js</code></pre><pre class="hljs"><code><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>(<span class="hljs-function">(<span class="hljs-params">resolve, reject</span>) =&gt;</span> {
setTimeout(<span class="hljs-function"><span class="hljs-params">()</span> =&gt;</span> { <span class="hljs-comment">// delay the response for 5s</span>
resolve({ <span class="hljs-attr">response</span>: newResponse });
}, <span class="hljs-number">5000</span>);
});
}
},
};</code></pre><h2 id="作为npm模块使用"><a class="header-link" href="#作为npm模块使用"></a>作为npm模块使用</h2>
<p>AnyProxy可以作为一个npm模块使用整合进其他工具。</p>
<blockquote>
<p>如要启用https解析请在代理服务器启动前自行调用<code>AnyProxy.utils.certMgr</code>相关方法生成证书,并引导用户信任安装。或引导用户使用<code>anyproxy-ca</code>方法。</p>
</blockquote>
<ul class="list">
<li>引入</li>
</ul>
<pre class="hljs"><code>npm i anyproxy@beta --save <span class="hljs-comment"># 4.0版正在beta中</span></code></pre><ul class="list">
<li>使用举例</li>
</ul>
<pre class="hljs"><code><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 = {
<span class="hljs-attr">port</span>: <span class="hljs-number">8001</span>,
<span class="hljs-attr">rule</span>: <span class="hljs-built_in">require</span>(<span class="hljs-string">'myRuleModule'</span>),
<span class="hljs-attr">webInterface</span>: {
<span class="hljs-attr">enable</span>: <span class="hljs-literal">true</span>,
<span class="hljs-attr">webPort</span>: <span class="hljs-number">8002</span>,
<span class="hljs-attr">wsPort</span>: <span class="hljs-number">8003</span>,
},
<span class="hljs-attr">throttle</span>: <span class="hljs-number">10000</span>,
<span class="hljs-attr">forceProxyHttps</span>: <span class="hljs-literal">false</span>,
<span class="hljs-attr">silent</span>: <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>, () =&gt; { <span class="hljs-comment">/* */</span> });
proxyServer.on(<span class="hljs-string">'error'</span>, (e) =&gt; { <span class="hljs-comment">/* */</span> });
proxyServer.start();
<span class="hljs-comment">//when finished</span>
proxyServer.close();</code></pre><ul class="list">
<li><p>Class: AnyProxy.proxyServer</p>
<ul class="list">
<li><p>创建代理服务器</p>
<pre class="hljs"><code><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 class="list">
<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 class="list">
<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 class="list">
<li>代理服务器启动完成</li>
<li>示例</li>
</ul>
<pre class="hljs"><code>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 class="list">
<li>代理服务器发生错误</li>
<li>示例</li>
</ul>
<pre class="hljs"><code>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 class="list">
<li>启动代理服务器</li>
<li>示例</li>
</ul>
<pre class="hljs"><code>proxy.start();</code></pre></li>
<li><p>Method: <code>close</code></p>
<ul class="list">
<li>关闭代理服务器</li>
<li>示例</li>
</ul>
<pre class="hljs"><code>proxy.close();</code></pre></li>
</ul>
</li>
<li><p>AnyProxy.utils.systemProxyMgr</p>
<ul class="list">
<li>管理系统的全局代理配置,方法调用时可能会弹出密码框</li>
<li>使用示例</li>
</ul>
<pre class="hljs"><code><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 class="list">
<li>管理AnyProxy的证书</li>
<li><code>AnyProxy.utils.certMgr.ifRootCAFileExists()</code><ul class="list">
<li>校验系统内是否存在AnyProxy的根证书</li>
</ul>
</li>
<li><code>AnyProxy.utils.certMgr.generateRootCA(callback)</code><ul class="list">
<li>生成AnyProxy的rootCA完成后请引导用户信任.crt文件</li>
</ul>
</li>
<li>样例</li>
</ul>
<pre class="hljs"><code> <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(<span class="hljs-function">(<span class="hljs-params">error, keyPath</span>) =&gt;</span> {
<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>, { <span class="hljs-attr">cwd</span>: certDir });
} <span class="hljs-keyword">else</span> {
exec(<span class="hljs-string">'open .'</span>, { <span class="hljs-attr">cwd</span>: 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>
<h2 id="关于anyproxy"><a class="header-link" href="#关于anyproxy"></a>关于AnyProxy</h2>
<ul class="list">
<li>AnyProxy是支付宝前端团队推出的开源产品</li>
<li>Change Log: <a href="https://github.com/alibaba/anyproxy/blob/master/CHANGELOG">https://github.com/alibaba/anyproxy/blob/master/CHANGELOG</a></li>
<li>代码库:<a href="https://github.com/alibaba/anyproxy">https://github.com/alibaba/anyproxy</a></li>
<li>issue反馈<a href="https://github.com/alibaba/anyproxy/issues">https://github.com/alibaba/anyproxy/issues</a></li>
</ul>
<h2 id="配置帮助"><a class="header-link" href="#配置帮助"></a>配置帮助</h2>
<h3 id="osx系统信任ca证书"><a class="header-link" href="#osx系统信任ca证书"></a>OSX系统信任CA证书</h3>
<ul class="list">
<li>类似这种报错都是因为系统没有信任AnyProxy生成的CA所造成的</li>
</ul>
<p class="img-container"><img src="https://zos.alipayobjects.com/rmsportal/CBkLGYgvoHAYwNVAYkpk.png" width="450" /></p>
<blockquote>
<p>警告CA证书和系统安全息息相关建议亲自生成并妥善保管</p>
</blockquote>
<p>安装CA</p>
<ul class="list">
<li><p>双击打开<em>rootCA.crt</em></p>
</li>
<li><p>确认将证书添加到login或system</p>
</li>
</ul>
<p class="img-container"><img src="https://zos.alipayobjects.com/rmsportal/bCwNUFFpvsmVuljQKrIk.png" width="350" /></p>
<ul class="list">
<li>找到刚刚导入的AnyProxy证书配置为信任Always Trust</li>
</ul>
<p class="img-container"><img src="https://zos.alipayobjects.com/rmsportal/HOmEElNGdoZEWFMLsTNT.png" width="700" /></p>
<h3 id="windows系统信任ca证书"><a class="header-link" href="#windows系统信任ca证书"></a>Windows系统信任CA证书</h3>
<p class="img-container"><img src="https://t.alipayobjects.com/tfscom/T1D3hfXeFtXXXXXXXX.jpg" width="700" /></p>
<h3 id="配置osx系统代理"><a class="header-link" href="#配置osx系统代理"></a>配置OSX系统代理</h3>
<ul class="list">
<li>在wifi高级设置中配置http代理即可</li>
</ul>
<p class="img-container"><img src="https://zos.alipayobjects.com/rmsportal/vduwhobSTypTfgniBvoa.png" width="500" /></p>
<h3 id="配置浏览器http代理"><a class="header-link" href="#配置浏览器http代理"></a>配置浏览器HTTP代理</h3>
<ul class="list">
<li>以Chrome的<a href="https://chrome.google.com/webstore/detail/padekgcemlokbadohgkifijomclgjgif">SwitchyOmega插件</a>为例</li>
</ul>
<p class="img-container"><img src="https://zos.alipayobjects.com/rmsportal/jIPZrKmqXRaSledQeJUJ.png" width="500" /></p>
<h3 id="配置ios/android系统代理"><a class="header-link" href="#配置ios/android系统代理"></a>配置iOS/Android系统代理</h3>
<ul class="list">
<li><p>代理服务器都在wifi设置中配置</p>
</li>
<li><p>iOS HTTP代理配置</p>
</li>
</ul>
<p class="img-container"><img src="https://zos.alipayobjects.com/rmsportal/tLGqIozhffTccUgPakuw.png" width="260" /></p>
<ul class="list">
<li>Android HTTP代理配置</li>
</ul>
<p class="img-container"><img src="https://zos.alipayobjects.com/rmsportal/YQtbQYVNuOszZGdAOauU.png" width="260" /></p>
</div>
</article>
<script src="//cdn.bootcss.com/zepto/1.2.0/zepto.min.js"></script>
<script>
window.onload = function(){
var itemList = [];
var targetMap = {};
$("[id]", ".main-content").map(function (index, heading) {
targetMap[heading.getAttribute('id')] = heading;
});
$("#j_toc li").map(function (index, item) {
if (item.className.indexOf('sidebar-header-2') >= 0 || item.className.indexOf('sidebar-header-3') >= 0) {
var targetName = item.firstChild.getAttribute('href').replace('#', '');
var targetItem = targetMap[targetName];
itemList.push({ target: targetItem, tocItem: item, top: $(targetItem).position().top });
}
});
var updateTocActive = function (e) {
var windowHeight = window.innerHeight;
//find the first item to match
var scrollYThres = window.scrollY + 200;
var target;
if (scrollYThres < 100) {
target = itemList[0].tocItem;
} else {
itemList.forEach(function (item, index) {
if (target) return;
if (index > 0) {
if (item.top >= scrollYThres) {
target = itemList[index - 1].tocItem;
}
}
});
}
$('.toc-active').removeClass('toc-active');
$(target).addClass('toc-active');
};
window.onscroll = updateTocActive;
updateTocActive();
}
</script>
</body>
</html>