我们相信:世界是美好的,你是我也是。平行空间的世界里面,不同版本的生活也在继续...

create-react-app项目里面,有个src/setupProxy.js文件,这个文件是如何代理【测试环境下】的网络接口请求?代码中的http-proxy-middleware,只能应用于接口请求么?带着问题阅读苏南大叔的文章。

苏南大叔:React项目,setupProxy.js如何生效?http-proxy-middleware - http-proxy-middleware
React项目,setupProxy.js如何生效?http-proxy-middleware(图5-1)

苏南大叔的“程序如此灵动”博客,记录苏南大叔的代码编程经验总结。本文测试环境:nodejs@20.18.0create-react-app@5.0.1react-router-dom@6.27.0react@18.3.1http-proxy-middleware@2.0.3

前文阅读

任何react项目里面,类似ajax的请求,都是本文的目标接口测试内容。参考文章:

本地项目为localhost:3000,远程接口服务器项目为localhost:3222。域名虽然相同,但是端口不一致,所以必须解决一个“跨域”的问题。

解决跨域的方式很多,在以前的解决方案,是在express接口中配置了cors。而本文描述的方案,就是create-react-app中的react-scripts所自带的src/setupProxy.js解决方案。

当然,本文还有个更加简单直接的跨域方案,直接在package.json里面配置proxy项目。参考文章:

代码配置

http-proxy-middleware库借助于node-http-proxy,用于将node服务器接收到的请求转发到目标服务器,实现代理服务器的功能。

生效途径

本文的src/setupProxy.js本身的功能就相当于上面的cors,并不需要接口服务器(express)端做跨域配置。
src/setupProxy.js文件,是react-scripts项目所约定俗成的文件名。只要符合规范,就可以被create-react-app创建的项目所识别。参考下面的代码截图。

苏南大叔:React项目,setupProxy.js如何生效?http-proxy-middleware - setupproxy
React项目,setupProxy.js如何生效?http-proxy-middleware(图5-2)

简单例子

这个代理代码的配置,很程式化,可以参考下面的范例。

const { createProxyMiddleware } = require("http-proxy-middleware");
module.exports = function (app) {
  app.use(
    // /sunan/plus/aa?bb=cc
    createProxyMiddleware("/sunan", {
      target: "http://localhost:3222",
      changeOrigin: true,
    }),
    // /api/sunan/plus/aa?bb=cc
    createProxyMiddleware("/api", {
      target: "http://localhost:3222",
      changeOrigin: true,
      pathRewrite: {
        // 匹配到就停止匹配,不继续匹配
        "^/api/sunan/plus/": "/sunan_plus/",
        "^/api/sunan/ojbk/": "/sunan_ojbk/",
        "^/api/": "",
      },
    })
  );
};

效果是这样的:

本地请求实际请求
localhost:3000/sunan/*localhost:3222/sunan/*
localhost:3000/api/sunan/plus/*localhost:3222/sunan_plus/*
localhost:3000/api/sunan/ojbk/*localhost:3222/sunan_objk/*
localhost:3000/api/*localhost:3222/*

参数解释:

  • changeOrigin: true就是相当于“跨域”设置,这个跨域的原理后续文章再做讨论。对于本文来说,无脑设置为true即可,没有什么理由设置为默认的false
  • pathRewrite,路径匹配规则。这里可以配置多条规则,并且从上往下,一旦匹配成功,则不再继续匹配。也就是说,并不是单纯的replace,有多少个地方,就替换多少次。功能很强大,但是基本上也用不到。因为,做接口的都是自己人,为啥自己人要难为自己人呢?对吧?生生的制造【正则表达式】的应用场景么?

新的配置例子

如果上面的例子看懂的话,这段例子也没有什么可以看的,就是再细分处理而已。下面的例子中,显示了可定制的headers,里面有签权token的传递方式。

下面的代码中,导出函数createProxyMiddleware():proxy重命名为了proxy()
const { createProxyMiddleware: proxy } = require("http-proxy-middleware");
module.exports = function (app) {
  app.use(
    // /login/sunan/ok?true=1
    proxy("/login", {
      target: "http://localhost:3222",
      changeOrigin: true,
      headers: {
        Authorization: "Bearer sunan_token",
      },
      pathRewrite: {
        "^/login/sunan/": "/superman/",
      },
    }),
    // /img/aaa.png
    proxy("/img/", {
      target: "http://localhost:3222",
      changeOrigin: true,
      pathRewrite: {
        "^/img/": "",
      },
    })
  );
};

在这个新的例子里面,请求的接口(文件)的匹配表是:

本地请求实际请求
localhost:3000/login/sunan/ok?true=1localhost:3222/superman/ok?true=1
localhost:3000/img/*.pnglocalhost:3222/*.png

测试代码

修改这个src/setupProxy.js文件,并不会像预想中的一样实施生效,需要再次【重启npm start】。具体的原因,这里就不深究了,没人会天天修改这个文件。

苏南大叔:React项目,setupProxy.js如何生效?http-proxy-middleware - 规则改写
React项目,setupProxy.js如何生效?http-proxy-middleware(图5-3)

react部分

测试的接口请求部分,是使用create-react-app创建的基础代码,使用ahooksuseRequest的官方demo修改版,发起不同的被proxy的请求。参考文章:

App.js

import React from "react";
import { useRequest } from "ahooks";
function fetchData(url = "/api/default") {
  console.log(url, "#########");
  return fetch(url)
    .then(async (response) => {
      if (!response.ok) {
        return await response.text();
      }
      return response.json();
    })
    .then((data) => {
      console.log(data);
      return data;
    });
}
function Status(props) {
  if (props.loading) {
    return <p>Loading...</p>;
  }
  if (props.error) {
    return <p>Error: {props.error.message}</p>;
  }
}
function Button(props) {
  return (
    <button onClick={props.run.bind({}, props.url)} disabled={props.loading}>
      {props.loading ? "loading" : props.url}
    </button>
  );
}
function App() {
  const { data, loading, error, run } = useRequest(fetchData);
  return (
    <div>
      <Button run={run} loading={loading} url="/sunan/123"></Button>
      <Button run={run} loading={loading} url="/api/sunan/plus/ss?bb=cc"></Button>
      <Button run={run} loading={loading} url="/api/sunan/ojbk/nn?cc=dd" ></Button>
      <Button run={run} loading={loading} url="/api/pku/ok?ss=nn"></Button>
      <Button run={run} loading={loading} url="/login/sunan/ok?oo=kk"></Button>
      <Status loading={loading} error={error}></Status>
      <pre>{!loading && !error && JSON.stringify(data, null, 2)}</pre>
      <img src="/img/aaa.png" />
    </div>
  );
}
export default App;

苏南大叔:React项目,setupProxy.js如何生效?http-proxy-middleware - react测试
React项目,setupProxy.js如何生效?http-proxy-middleware(图5-4)

express部分

另外,本文的代码正确执行,需要一个接口服务配合。这里使用express.js来做这件事情。苏南大叔定制的express,接管了所有的请求,然后显示req的相关信息,已验证接口是否正确请求。

express.js:

const express = require("express");
const app = express();
app.use(express.static("public2"));
app.all("*", (req, res) => {
  const authHeader = req.headers["authorization"];
  const token = authHeader && authHeader.split(" ")[1];
  ret = {
    host: req.headers.host,
    url: req.url,
    path: req.path,
    method: req.method,
    token: token + "," + (token === "sunan_token"),
    time: Date.now().toString().slice(-6),
  };
  res.send(JSON.stringify(ret));
});
const server = app.listen(process.env.PORT || 3222, () => {
  const port = server.address().port;
  console.log("http://localhost:%d", port);
});

注意这里的代码,没有配置cors。并且为了匹配静态资源,设置了静态资源目录public2。例如:这里演示的被“proxy”的图片aaa.png,位于3222端口这边的express项目下的public2目录下面。

苏南大叔:React项目,setupProxy.js如何生效?http-proxy-middleware - 还能代理静态资源
React项目,setupProxy.js如何生效?http-proxy-middleware(图5-5)

文章内容的主要目标是接管网络接口请求,实际上,任何不存在的请求。无论接口、图片、css文件、js文件等,本项目中不存在的资源请求,都可以被http-proxy-middleware所接管。

build之后 等价物

值得特别说明的是:npm run build之后,这个端口的代理功能,就是由nginx进行配置的了。目前的src/setupProxy.js文件是没有什么用的了。

单就接口中转这件事来说,使用这么专业的代码,真的是杀鸡用宰牛刀了。因为普通的node里面的fetch()请求/php端的file_get_contents(),就能做到这个效果。跨域啥的,完全不惧。为啥还非要发明个changeOrigin: true呢?

结语

http-proxy-middleware不但可以应用在react-scripts支持的项目中,在其它项目里面也可以做到类似的资源代理请求功能的。参考后续文章。

如果本文对您有帮助,或者节约了您的时间,欢迎打赏瓶饮料,建立下友谊关系。
本博客不欢迎:各种镜像采集行为。请尊重原创文章内容,转载请保留作者链接。

 【福利】 腾讯云最新爆款活动!1核2G云服务器首年50元!

 【源码】本文代码片段及相关软件,请点此获取更多信息

 【绝密】秘籍文章入口,仅传授于有缘之人   react