原生html项目未使用框架,配置代理解决本地开发接口跨域--http-proxy-middleware

289 阅读3分钟

公司一个非常老的项目需要增加需求,使用的原生html、js、css,没有使用react、vue之类的框架的情况下使用http-proxy-middleware拦截请求进行代理

初始化package.json

首先你的电脑上要有node环境,控制台输出一下 输入npm init根据提示输入项目信息(一路回车就好,也可以直接复制

C:\Web\test>node -v
v18.16.1 //输出版本号就有node环境

C:\Web\test>npm init //初始化package.json
This utility will walk you through creating a package.json file.
It only covers the most common items, and tries to guess sensible defaults.

See `npm help init` for definitive documentation on these fields
and exactly what they do.

Use `npm install <pkg>` afterwards to install a package and
save it as a dependency in the package.json file.

Press ^C at any time to quit.
package name: (test) test
version: (1.0.0)
description:
entry point: (index.js)
test command:
git repository:
keywords:
author:
license: (ISC)
About to write to C:\Web\test\package.json:

{
  "name": "test",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC"
}


Is this OK? (yes) yes

C:\Web\test>

安装依赖

输入npm install nodemon http-proxy-middleware

nodemon的作用是你本地代码发生变化时自动更新服务

http-proxy-middleware是代理发送出去的请求

C:\Web\test>npm install nodemon http-proxy-middleware

added 39 packages in 8s

5 packages are looking for funding
  run `npm fund` for details

添加启动命令

安装结束在package.json scripts 处添加 "dev": "nodemon index.js"(这样比较优雅)

{
  "name": "test",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "dev": "nodemon index.js"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "http-proxy-middleware": "^3.0.2",
    "nodemon": "^3.1.7"
  }
}

编写入口文件

入口文件为index.js,在根目录创建index.js

使用node的path得到文件地址,fs模块读取文件,os模块获取当前局域网网关,http模块将读到的文件映射到局域网

需要代理的真实域名在注释处替换即可

const http = require('http');
const fs = require('fs');
const url = require('url');
const path = require('path');
const os = require('os');
const { createProxyMiddleware: proxyMiddleWare } = require('http-proxy-middleware');

// 监听所有网络接口
const hostname = getLocalIp();
const port = 3000;

const server = http.createServer((req, res) => {
  res.statusCode = 200;
  const parsedUrl = url.parse(req.url, true);
  const filePath = path.join(__dirname, parsedUrl.pathname);

  if (parsedUrl.pathname.startsWith('/api1')) {
    //拦截'/api'开头的请求进行代理
    console.log('代理api1');
    const proxyMiddleware = proxyMiddleWare({
      target: 'https://sues.cn/', //目标域名既你要代理的域名
      changeOrigin: true,
      secure: false,
      pathRewrite: {
        '^/api1': '',
      },
      onProxyReq: (proxyReq, req, res) => {
        proxyReq.setHeader('Cookie', 'JSESSIONID=62E0AA24BE5B6196399E853530431277');
      },
    });
    return proxyMiddleware(req, res, () => {
      res.writeHead(500, { 'Content-Type': 'text/plain' });
      res.end('Proxy failed');
    });
  }

  if (parsedUrl.pathname.startsWith('/api2')) {
    //拦截'/api2'开头的请求进行代理
    console.log('代理api2');
    const proxyMiddleware = proxyMiddleWare({
      target: 'https://workflow.cn/', //目标域名既你要代理的域名
      changeOrigin: true,
      secure: false,
      pathRewrite: {
        '^/api2': '',
      },
      onProxyReq: (proxyReq, req, res) => {
        proxyReq.setHeader('Cookie', 'JSESSIONID=62E0AA24BE5B6196399E853530431277');
      },
    });
    return proxyMiddleware(req, res, () => {
      res.writeHead(500, { 'Content-Type': 'text/plain' });
      res.end('Proxy failed');
    });
  }

  fs.readFile(filePath, (err, data) => {
    if (err) {
      if (err.code === 'ENOENT') {
        res.writeHead(404, { 'Content-Type': 'text/plain' });
        res.end('404 Not Found');
      } else {
        res.writeHead(500, { 'Content-Type': 'text/plain' });
        res.end('500 Internal Server Error');
      }
      return;
    }

    const contentType = getContentType(filePath);
    res.setHeader('Content-Type', contentType);
    res.end(data);
  });
});

server.listen(port, hostname, () => {
  console.log(`Server running at http://${hostname}:${port}/`);
});

// 获取当前局域网 IP 地址
function getLocalIp() {
  const interfaces = os.networkInterfaces();
  for (const name of Object.keys(interfaces)) {
    for (const interface of interfaces[name]) {
      const { address, family, internal } = interface;
      if (family === 'IPv4' && !internal && address.includes('192.168')) {
        return address;
      }
    }
  }
  return 'http://localhost/';
}
//获取资源类型
function getContentType(filePath) {
  const ext = path.extname(filePath).toLowerCase();
  switch (ext) {
    case '.html':
      return 'text/html';
    case '.css':
      return 'text/css';
    case '.js':
      return 'application/javascript';
    case '.json':
      return 'application/json';
    case '.png':
      return 'image/png';
    case '.jpg':
    case '.jpeg':
      return 'image/jpeg';
    case '.gif':
      return 'image/gif';
    default:
      return 'application/octet-stream';
  }
}

启动

输入npm run dev启动!

会打印出你当前网关的局域网,我这里是http://192.168.61.87:3000/按照你当前项目目录访问

C:\Web\test>npm run dev

> test@1.0.0 dev
> nodemon index.js

[nodemon] 3.1.7
[nodemon] to restart at any time, enter `rs`
[nodemon] watching path(s): *.*
[nodemon] watching extensions: js,mjs,cjs,json
[nodemon] starting `node index.js`
Server running at http://192.168.61.87:3000/

需要代理的请求开头一定要和拦截的保持一致!

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>http-proxy-middleware</title>
  </head>
  <body>
    <h1>原生html使用http-proxy-middleware代理,解决接口跨域</h1>
    <button id="send">发送请求</button>
    <button id="send2">发送请求</button>
  </body>
  <script>
    const context = '/api1';
    const context2 = '/api2';
    const api = {
      http1: context + '/getUserInfo',
      http2: context2 + '/getUserInfo2',
    };

    document.querySelector('#send').addEventListener('click', async function () {
      const res = await fetch(api.http1);
      console.log(res);
    });
    document.querySelector('#send2').addEventListener('click', async function () {
      const res = await fetch(api.http2);
      console.log(res);
    });
  </script>
</html>

发送请求代理成功时可以看到终端打印

运行截图

运行图片.png

运行图片2.png

运行图片3.png

仓库地址

gitee.com/ZHYCH992/De…

稀土掘金搜索 ZHYCH 即可找到我学习更多前端小技巧,未经作者允许请勿转载