使用 Whistle 作为 API 服务网关
- 2019 年 10 月 11 日
- 笔记
最近写了一款 React 的工具,能拉取团队成员 Jira 上的 Task 和 Bug,根据其 Task 的 Efforts 时长和 Bug 的修复时长,计算对应的绩效指标。
今天给大家介绍下,我是如何在这个项目中利用 Whistle 来实现 API 服务网关的(还不知道 Whistle ?看这里)。
在项目开发过程中,前端本地的 webpack 会启动服务并监听一个端口(例如 8000),浏览器访问 http://localhost:8000 即可进行页面的开发预览。
假如你的 Jira 站点为 https://jira.example.com ,此时,需要浏览器能直接对 Jira 的 Rest API 服务(https://jira.example.com/rest/api/)发起请求。
1. CORS 合法化配置
当浏览器向与当前页面域名不同的域名发起 API 请求时,会触发 CORS 策略,以确保请求是被目标服务所允许的。
本地开发时的域名是 localhost,API 服务是 example.com,所以会触发 CORS 及其 Preflight Request 策略。

Whistle 提供了 resCors 协议可以很方便的为 response 加上 CORS 相关的 Header(Access-Control-Request-* )。
如下图配置,我们可以设置允许来源 origin 为任意站点(*),允许自定义 Header Authorization 和 Content-Type 的使用:
https://jira.example.com/rest/api resCors://{resCorsTest.json} delete://req.headers.User-Agent ```resCorsTest.json { "origin": "*", "headers": "authorization,content-type", } ```
同时,我们还使用 delete 协议删除了请求头中的 UA 头信息(req.headers.User-Agent),让 API 服务无法判断出请求的发起方是否为浏览器(注意:Jira Rest API 会针对浏览器开启 XSRF Check)。
2. HTTP Header/Body 的过滤与修改
CORS 合法化配置完成后,浏览器已经可以成功发起跨域 API 请求,但在 console 控制台中,还有上图中的黄色 warning 需要消除。
这个 warning 的原因在于,options 请求的响应头中设置了 X-Content-Type-Options: nosniff
,我们可以使用 includeFilter 针对 options HTTP Method,删除掉这个 Header:
https://jira.example.com/rest/api includeFilter://m:options delete://res.headers.X-Content-Type-Options
如有需要,我们还可以利用 headerReplace 将某个 Header 替换成其他的值,以及使用 resBody 来设置 response 的 body 内容:
https://jira.example.com/rest/api headerReplace://res.Content-Type:/.*/=application/json resBody://({})
3. 同域网关
事实上,Whistle 作为代理网关,可以更加方便的绕过 CORS 策略限制。
我们只需为我们的静态页面和 API 服务设置一个相同的自定义域名,然后全部交给 Whistle 即可。
假如这里我们的自定义域名为:http://my.jira.com ,我们只需把对 http://my.jira.com/rest/api 的访问转发到 https://jira.example.com/rest/api 即可:
http://my.jira.com/rest/api https://jira.example.com/rest/api delete://headers.User-Agent http://my.jira.com 127.0.0.1:8000
(注意:/rest/api 需要配置在前面,确保优先命中)
由于 Rest API 的域名和当前页面设置为同域,所以不会产生 CORS 与 Preflight Request 限制。
在本地开发完成后,我们可以使用 file 协议,直接将自定义域名映射到静态文件目录上。另外,由于需要在 JS 代码中隐藏 Jira HTTP 鉴权的用户名和密码,我们可以通过 auth 协议将这部分信息配置在 Whistle 网关中。以下是完整配置:
http://my.jira.com/rest/api https://jira.example.com/rest/api delete://headers.User-Agent auth://your-username:your-password http://my.jira.com file:///path/to/your/project/dist/
同域网关除了以上这种配置外,还有另外一种逆向思路:
将静态页面域名配置成实际的 API 服务域名,借助 xfile 协议,我们可以将未命中的请求全部转发到实际的线上服务,只需以下一行配置:
https://jira.example.com/ xfile:///path/to/your/project/dist/
需要注意的是,以上这种方法需要安装 Whistle CA 证书,用于解析 HTTPS 协议。
怎么样?把 Whistle 作为 API 服务网关,而不需要使用 Node 或 Nginx 服务来转发,是不是既简单又方便?赶紧试试吧:)