logo

鱼肚的博客

Don't Repeat Yourself

使用Node.js搭建一个简单的转发服务

背景

最近因工作需要,想要在内网开发环境访问到npm包的内部文件。

我的第一反应当然是使用大名鼎鼎的unpkg啦,它可以方便地访问到任意版本的任意文件,甚至还支持dist-tag自动跳转。

然而悲剧的是公司的内网环境连接unpkg有一些问题,在没翻墙的机器上,unpkg的机器打不开。

此时的我面临三个选择:

  • 想办法让unpkg能连通
  • 内网搭建一个unpkg-server
  • 不提供或使用泛用途的unpkg服务,只针对指定 npm 包,做上传到静态文件服务的处理。

为了懒省事,且方便使用,我还是选择了让unpkg能连通。

搭建代理

这种小服务用Node.js搭建再好不过。

最初我想做一个用 query 参数传URL的服务,访问方式类似于http://myproxy.com/?target=https://baidu.com,但是搜索了几个热门的 http 代理相关包,好像都不太支持这样的用法。

所以我换成了下面的路由的形式:

http://myproxy.com/unpkg/<package>@<version>/<file-path>

源代码如下:

1const app = require('express')();
2const { createProxyMiddleware } = require('http-proxy-middleware');
3
4app.use('/unpkg', createProxyMiddleware({
5  target: 'https://unpkg.com/',
6  changeOrigin: true,
7  pathRewrite: {'^/unpkg' : ''},
8  onProxyRes: (proxyRes, req, res) => {
9    proxyRes.headers.location = '/unpkg' + proxyRes.headers.location
10  }
11}));
12
13app.listen(process.env.PORT || 3000)

这里我做了两个特殊的设置,一个是pathRewrite,另一个是onProxyRes,下面分别解释下。

pathRewrite

默认情况下,代理的时候只是替换host地址,path是全部保留的。而我们的代理服务中使用了 /unpkg作为路由,转发的时候需要去掉。

这个pathRewrite的选项,就是用于改写地址的。改写的规则可以多种多样,上面演示的只是最基本的用法。

onProxyRes

unpkg中支持使用dist-tag进行访问,即 @<version>处换成@<dist-tag>。dist-tag对应的内容是经常变化的,不能加强制缓存。而为了节省流量,unpkg是倾向于使用强制缓存的,所以它做了一次跳转,从内容不固定的 dist-tag 跳转到此 dist-tag 当前指向的版本号,然后在跳转后的链接中,再返回具体的文件内容,此时就可以放心地加缓存了。

这里onProxyRes的使用就是为了应对这种场景,因为中间有一次跳转,跳转的地址是 unpkg的地址。而我们的代理服务中,地址部分比unpkg的原生地址多了个/unpkg的前缀。如果不做处理,就会跳转到错误的地址。

这里的处理就是将跳转地址加工一下,在前面加上我们给定的前缀,使得跳转后的地址还能正确转发到unpkg。

代码很简单,希望对大家有所帮助。