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

create-react-app的默认模版中,是没有接口请求功能的。但是正常的业务逻辑中,接口请求功能是必不可少的。并且接口一般都是由第三方工程(甚至都已经脱离了nodejs的范畴)所提供的。所以,在cra的默认项目中,就必不可少的面临着接口跨域请求的问题。

苏南大叔:如何理解package.json中由react-scripts提供的proxy代理项? - react-scripts-proxy
如何理解package.json中由react-scripts提供的proxy代理项?(图5-1)

苏南大叔的“程序如此灵动”博客,记录苏南大叔的编程感悟感想。本文测试环境:win10node@16.14.2react@18.2.0create-react-app@5.0.1react-scripts@5.0.1

是否符合实际需求?

因为正常情况下来说,在最终的产品部署的时候,请求接口的代码主体和各种接口,都会被nginx整合在一起,从而并不会产生跨域的问题。参考文章:

create-react-app的重要组成部分react-scripts中,是通过在package.json中,增加proxy项目来解决这个问题的。本文的解决方案,比较简单。所以并不是万能的,下面的情况下,您不必使用本文的方案。

  • 可以以CORS的方式,解决接口跨域的问题。
  • 或者有多个接口服务器的地址,需要配置,那么需要的解决方案是:http-proxy-middleware

官方文档的说法是:”To tell the development server to proxy any unknown requests to your API server in development, add a proxy field to your package.json“

proxy可以被配置为httphttps或者websocketwebsocket的情况,待后续文章补充。

proxy配置为字符串

配置为字符串的方式,最简单实用,适合于目标接口服务器就仅仅是一个的时候。大对数情况下,就是这样的配置。现在假设:本地的接口请求地址是:/ping。因为本地没有服务器去响应这个/ping请求,所以需要配置个proxy来解决这个问题。

{
  //...
  "proxy": "<api_host>",
  //...
}

总之,这是个接口地址拼接的问题,在proxy配置好的隐式部分,+ 接口代码里面写的显式部分,就是真正的接口地址。

情况一

目标接口服务器的真实请求地址是:<api_host>/ping,(也就是说纯地址部分,一致。都是/ping)。
那么,package.json中的proxy项目的配置就是:

{
  //...
  "proxy": "http://localhost:8888",
  //...
}

情况二

目标接口服务器的真实请求地址是:<host>/api/ping,(也就是说纯地址部分,部分一致,目标接口存在着父目录/api/)。
那么,package.json中的proxy项目的配置就是:

{
  //...
  "proxy": "http://localhost:8888/api/",
  //...
}

测试代码

主要的需求就是:在create-react-apprun start的时候,请求成功目标接口。这里假设你已经初始化好了相关项目。

create-react-app test

第一步,接口服务器

npm i express --save

这里先使用express来做个接口服务器,文件是/server.js

const express = require("express");
const bodyParser = require("body-parser");
const path = require("path");

const app = express();
app.use(express.static(path.join(__dirname, "build")));

app.get("/api/ping", function (req, res) {
  return res.send("pong,加油"+req.query["name"]);
});
app.get("/api/pingping", function (req, res) {
  return res.send("pongpong,加油"+req.query["id"]);
});
app.get("/", function (req, res) {
  res.sendFile(path.join(__dirname, "build", "index.html"));
});

app.listen(process.env.PORT || 8888);

可以参考文章:

启动之后,就可以获得接口服务器的地址http://localhost:8888/了。

node server.js
express的引入,有两种,一个是require,另外一个是import。如果是import的话,那么可能就不能这样简单的使用node来启动了。待续。

苏南大叔:如何理解package.json中由react-scripts提供的proxy代理项? - express服务器
如何理解package.json中由react-scripts提供的proxy代理项?(图5-2)

第二步,请求接口

修改src/App.js,创建接口的请求代码,可以使用axios或者fetch,参考文章:

npm i axios --save

后面的代码,因为是基于create-react-app的,会自动被babel转化,所以使用了import,而不是require

import "./App.css";
import axios from "axios";

function App() {
  return (
    <div className="App">
      <button onClick={test.bind(this)}>接口一</button>
      <button onClick={test2}>接口二</button>
      <button onClick={test3.bind(this)}>接口三</button>
    </div>
  );
}

export default App;

const params = { id: 1, name: "sunan" };
function test() {
  axios
    .get("/ping", { params })
    .then((response) => {
      console.log(response.data);
    })
    .catch((error) => {
      console.error(error);
    });
}

function test2() {
  let url_fetch = "/pingping" + "?" + new URLSearchParams(params).toString();
  fetch(url_fetch)
    .then(function (response) {
      console.log(response);
      return response.text();
    })
    .then(function (data) {
      console.log(data);
    })
    .catch(function (e) {
      console.log("Oops, error");
    });
}

function test3() {
  axios.get("/ping", { params }).then(
    (response) => {
      console.log(response.data);
    },
    (error) => {
      console.log(error);
    }
  );
}

苏南大叔:如何理解package.json中由react-scripts提供的proxy代理项? - react主代码
如何理解package.json中由react-scripts提供的proxy代理项?(图5-3)

第三步,配置proxy

修改package.json文件,增加字样:

{
   //...
  "proxy": "http://localhost:8888/api/"
}

苏南大叔:如何理解package.json中由react-scripts提供的proxy代理项? - package-proxy
如何理解package.json中由react-scripts提供的proxy代理项?(图5-4)

最后一步,运行测试

然后在保持node server.js运行的同时,再次运行项目代码:

npm start

苏南大叔:如何理解package.json中由react-scripts提供的proxy代理项? - 运行截图
如何理解package.json中由react-scripts提供的proxy代理项?(图5-5)

特别说明

需要特别说明的是:理论上来说,<本地host>/ping就等于远程<api_host>/ping了。但是,实际测试中就会发现,在地址栏里面敲<本地host>/ping的话,是没有任何反应的。而在使用axios或者fetchajax函数的时候,却可以正常访问接口。可见,react-scripts对于proxy生效的问题,还是有用特别的钩子函数来实现的。

官方文档的说法是:"The development server will only attempt to send requests without text/html in its Accept header to the proxy."

package.json中的proxy项目,也只是被用做代码本地调试的时候,尽力的去模拟最终的部署环境的请求方式而已。一旦这个react项目被build之后,这个proxy是并【不会】继续生效的。

相关文章

结束语

结论就是:create-react-app项目里面,配置在package.json里面的proxy选项,就是为了【本地调试】不同域下的接口的时候,避免产生跨越问题,而产生的一种简单的解决方案。虽然并不能解决所有的接口跨越问题,但是,还是能解决大部分问题的。构建了之后,这个proxy选项就会失效,可能需要使用nginx等工具继续配置代理相关接口。

更多react相关项目文章,请参考:

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

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

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

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