如何理解package.json中由react-scripts提供的proxy代理项?
发布于 作者:苏南大叔 来源:程序如此灵动~create-react-app
的默认模版中,是没有接口请求功能的。但是正常的业务逻辑中,接口请求功能是必不可少的。并且接口一般都是由第三方工程(甚至都已经脱离了nodejs
的范畴)所提供的。所以,在cra
的默认项目中,就必不可少的面临着接口跨域请求的问题。
苏南大叔的“程序如此灵动”博客,记录苏南大叔的编程感悟感想。本文测试环境:win10
,node@16.14.2
,react@18.2.0
,create-react-app@5.0.1
,react-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
可以被配置为http
、https
或者websocket
。websocket
的情况,待后续文章补充。
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-app
的run 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
来启动了。待续。
第二步,请求接口
修改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);
}
);
}
第三步,配置proxy
修改package.json
文件,增加字样:
{
//...
"proxy": "http://localhost:8888/api/"
}
最后一步,运行测试
然后在保持node server.js
运行的同时,再次运行项目代码:
npm start
特别说明
需要特别说明的是:理论上来说,<本地host>/ping
就等于远程<api_host>/ping
了。但是,实际测试中就会发现,在地址栏里面敲<本地host>/ping
的话,是没有任何反应的。而在使用axios
或者fetch
等ajax
函数的时候,却可以正常访问接口。可见,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
是并【不会】继续生效的。
相关文章
- https://newsn.net/say/create-react-app.html
- https://newsn.net/say/express.html
- https://create-react-app.dev/docs/proxying-api-requests-in-development/
结束语
结论就是:create-react-app
项目里面,配置在package.json
里面的proxy
选项,就是为了【本地调试】不同域下的接口的时候,避免产生跨越问题,而产生的一种简单的解决方案。虽然并不能解决所有的接口跨越问题,但是,还是能解决大部分问题的。构建了之后,这个proxy
选项就会失效,可能需要使用nginx
等工具继续配置代理相关接口。
更多react
相关项目文章,请参考:
本博客不欢迎:各种镜像采集行为。请尊重原创文章内容,转载请保留作者链接。