前端如何使用node做代理

770 阅读1分钟

前端代理

代理工具:charles,fiddler,whistle...

1. 本地node服务作为系统代理

1.1、起一个node服务,并手动设置系统代理

代理设置:Mac系统设置 > 网络 > WiFi > 代理 > 网页代理(HTTP)

  • 服务器:你的ip地址
  • 端口号:8886(node服务端口)

所有http请求响应内容为request url:${req.url}

import http from 'http'

const server = http.createServer((req, res) => {
  console.log(`request url:${req.url}`)
  res.setHeader('Content-Type', 'text/html;charset=utf-8')
  res.end(`request url:${req.url}`)
})
server.listen(8886)
1.2、使用http-node转发到目标服务器,你可以针对请求不同的页面路径代理不同的目标源,还可以添加自定义响应头...
import type { IncomingMessage } from 'http'
import http from 'http'
import HttpProxy from 'http-proxy'
import url from 'url'

type Protocol = 'http' | 'https'

const getProtocol = (req: IncomingMessage): Protocol => {
  if ((req.socket as any).encrypted) {
    return 'https'
  }
  const proto = req.headers['X-Forwarded-Proto'] as Protocol | undefined
  return typeof proto !== 'undefined' ? proto!.split(/\s*,\s*/, 1)[0] as Protocol : 'http';
}

const server = http.createServer((req, res) => {
  const origin = `${getProtocol(req)}://${req.headers['host']}`
  const path = url.parse(req.url || '').path

  if (path?.match(/^\/api1/)) {
    // 代理其他源
  }
  if (path?.match(/^\/api2/)) {
    // 代理其他源
  }

  const proxyServer = new HttpProxy()
  proxyServer.on('proxyRes', (proxyRes) => {
    if (req.headers['host'] === 'xxx.com') {
      // 添加自定义响应头
      proxyRes.headers['X-my-custom-field'] = '11111-------11111'
    }
  })
  proxyServer.web(req, res, {
    target: origin,
    changeOrigin: true
  })
})

server.listen(8886)

2. vite、webpack工具代理配置

早期项目都是用webpack-dev-server(依赖express中间件http-proxy-middleware),这里举例vite的使用

// vite.config.ts
import { defineConfig } from "vite";

export default defineConfig((_config) => {
  return {
    // ...
    server: {
      proxy: {
        "/api": {
          target: "https://api.xxx.com",
          changeOrigin: true,
          configure(proxy, options) {
            // proxy就是基于http-proxy创建的代理对象,vite依赖http-proxy
            proxy.on("proxyRes", (proxyRes) => {
              proxyRes.headers["X-my-custom-field"] = "111----111";
            });
          },
        },
      },
      hmr: {
        overlay: false,
      },
      host: "0.0.0.0",
    },
  };
});

3. Whistle代理工具

Whistle类似charles等其他代理工具,其主要是作为一款跨平台web调试代理工具,非常强大好用,官方文档

Whistle原理类似node代理,它与charles类似,安装完证书,即可代理https,以下是Whistle客户端工具Rules的配置,常用的功能见官方文档Whistle常用功能

# 转发:本地ip:port可以通过域名进行访问
# 调试不同端的环境(浏览器,微信webview,微信公众号开发,原生app webview h5,...)
172.16.22.117:5173 taobao.com test.com xxx.com

# 重定向
chaoshi.jd.com/aaa redirect://https://chaoshi.jd.com/liangfan

# 模拟bad request
taobao.com replaceStatus://400

# 针对所有请求新增跨域请求头(xhr请求,未绑定域名的阿里oss地址)
*/ resHeaders://{cors}

# 百度站点自定义html内容
www.baidu.com htmlBody://{test.html}

4. 代理请求头设置

看 http-proxy怎么处理的

XHeaders: function XHeaders(req, res, options) {
  if(!options.xfwd) return;

  var encrypted = req.isSpdy || common.hasEncryptedConnection(req);
  var values = {
    for  : req.connection.remoteAddress || req.socket.remoteAddress,
    port : common.getPort(req),
    proto: encrypted ? 'https' : 'http'
  };

  ['for', 'port', 'proto'].forEach(function(header) {
    req.headers['x-forwarded-' + header] =
      (req.headers['x-forwarded-' + header] || '') +
      (req.headers['x-forwarded-' + header] ? ',' : '') +
      values[header];
  });

  req.headers['x-forwarded-host'] = req.headers['x-forwarded-host'] || req.headers['host'] || '';
},

nginx做转发也需要处理

http {
  server {
    location ~* ^/(api|gw) {
      proxy_pass 代理源;
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header X-Forwarded-Proto $proxy_add_x_forwarded_proto;
    }
  }
}