在之前的一篇文章中,详细介绍了解决跨域的两种方式,今天主要讲在react脚手架中发送Ajax请求解决跨域的另外两种代理方式,有需要的话可以耐心看完哦
集成第三方ajax库
(或自己封装)axios
: 轻量级, 建议使用
需求:
点击按钮,向服务器发送请求,获取学生数据
1️⃣首先需要在vscode安装axios
npm install axios
2️⃣然后使用node+express
搭建一个服务器:
server1.js:
const express = require('express')
const app = express()
//服务器搭建好了,并且服务一旦开启就会被use中间件监听到,打印出“有人请求服务器1了”
app.use((request, response, next) => {
console.log('有人请求服务器1了');
console.log('请求来自于', request.get('Host'));
console.log('请求的地址', request.url);
next()
})
app.get('/students', (request, response) => {
const students = [
{ id: '001', name: 'tom', age: 18 },
{ id: '002', name: 'jerry', age: 19 },
{ id: '003', name: 'tony', age: 120 },
]
response.send(students)
})
//服务器开启在5000端口
app.listen(5000, (err) => {
if (!err) console.log('服务器1启动成功了,请求学生信息地址为:http://localhost:5000/students');
})
由于浏览器地址栏默认发送的就是get请求,我们可以在地址栏输入:http://localhost:5000/students
按下回车键,查看服务是否可以成功返回数据:
3️⃣发送请求获取数据:
import React, { Component } from 'react'
import axios from 'axios'
export default class App extends Component {
getStudentData = () => {
axios.get('http://localhost:5000/students').then(
response => { console.log('成功了', response.data) },
error => { console.log('失败了', error) }
)
}
render() {
return (
<div>
<button onClick={this.getStudentData}>点我获取学生数据</button>
</div>
);
}
}
当点击按钮时,控制台显示报错:
No ‘Access-Control-Allow-Origin’ header:说明跨域了,违背了同源策略…由于react脚手架运行在3000端口,但是发送请求的服务器在5000端口,形成了跨端口访问的问题,违背了同源策略,所以访问失败。
如何解决呢?在react脚手架里通过代理
来解决。
代理是什么?所谓"中间人",3000端口运行着一个react脚手架,还运行着一个微小的服务器,就是”中间人“。
产生跨域本质上是ajax引擎把服务器返回的数据给拦住了,原先的react脚手架有Ajax引擎,把服务器返回的数据给拦住了。而代理没有Ajax引擎,不存在跨域的问题。
实现过程:
react脚手架3000发送请求给代理3000,代理3000转发请求给服务器5000,服务器5000返回响应的数据给代理3000,代理3000再把数据传给react脚手架3000。(代理好比中介)
方法一(最简单):
在package.json
中加一行代码(如下图),意思是:代理给5000端口的地址发送请求。
然后原先axios给5000端口号发送请求,需要改为3000端口号
,因为代理的端口号是3000。
getStudentData = () => {
axios.get('http://localhost:3000/students').then(
response => { console.log('成功了', response.data) },
error => { console.log('失败了', error) }
)
}
运行结果:
那么问题来了?axios所有的请求都转发给5000端口吗?答案:不是。
3000端口有的资源,代理服务器就不会转发给5000端口了,如果当请求了3000不存在的资源时,那么该请求会转发给5000。
总结说明:
- 优点:配置简单,前端请求资源时可以不加任何前缀。
- 缺点:不能配置多个代理。
- 工作方式:上述方式配置代理,当请求了3000不存在的资源时,那么该请求会转发给5000 (优先匹配前端资源)
当react脚手架要向多个服务器请求数据呢?上述方法就行不通了。接下来看方法二
方法二:
再增加一个服务器,模拟多个服务器进行测试。
server2.js
(5001端口)
const express = require('express');
const app = express()
app.use((request, response, next) => {
console.log('有人请求服务器2了');
next()
})
app.all('/cars', (request, response) => {
const cars = [
{ id: '001', name: '奔驰', price: 199 },
{ id: '002', name: '马自达', price: 109 },
{ id: '003', name: '捷达', price: 120 },
]
response.send(cars)
})
app.listen(5001, (err) => {
if (!err) console.log('服务器2启动,已经监听到5001端口...')
})
第一步:
在src文件夹下,新建一个文件,名为:setupProxy.js
(名字固定,react脚手架会自动找到此文件,加到webpack的配置里,而webpack配置使用的都是node中的语法,也就是CommonJS语法)。
所以setupProxy文件里面不能用前端人员熟悉的ES6的语法,需要用CommonJS语法(CommonJS语法是前端模块化的一种规范)。
第二步:
编写setupProxy.js
配置代理规则:
// 建立代理
const { createProxyMiddleware } = require('http-proxy-middleware')
module.exports = function (app) {
app.use(
// use()函数能传多个参数
createProxyMiddleware('/api1', {//遇见/api1前缀的请求,就会触发该代理配置(所有带有/api1前缀的请求都会转发给5000)
target: 'http://localhost:5000',
changeOrigin: true,
pathRewrite: { '^/api1': '' }
}),
createProxyMiddleware('/api2', {
target: 'http://localhost:5001',
changeOrigin: true,
pathRewrite: { '^/api2': '' }
})
)
}
对配置的属性解释:
target:
请求转发给谁(能返回数据的服务器地址)
changeOrigin:
控制服务器收到的请求头中Host字段的值(Host字段:标识着本次请求是从哪发出的)
⭐changeOrigin设置为true时,服务器收到的请求头中的host为:localhost:5000
⭐changeOrigin设置为false时,服务器收到的请求头中的host为:localhost:3000
⭐changeOrigin默认值为false,但我们一般将changeOrigin值设为true
pathRewrite: { '^/api1': '' }:
(必须写)重写请求路径:将请求路径里的/api1替换成一个空字符串,去除请求前缀,保证交给后台服务器的是正常请求地址。
说明:
- 优点:可以配置多个代理,可以灵活的控制请求是否走代理。
- 缺点:配置繁琐,前端请求资源时必须加前缀。
App.jsx:
import React, { Component } from 'react'
import axios from 'axios'
export default class App extends Component {
getStudentData = () => {
axios.get('http://localhost:3000/api1/students').then(
response => { console.log('成功了', response.data) },
error => { console.log('失败了', error) }
)
}
getCarData = () => {
axios.get('http://localhost:3000/api2/cars').then(
response => { console.log('成功了', response.data) },
error => { console.log('失败了', error) }
)
}
render() {
return (
<div>
<button onClick={this.getStudentData}>点我获取学生数据</button>
<button onClick={this.getCarData}>点我获取汽车数据</button>
</div>
);
}
}
总体效果:
今天的分享就到这里啦 ✨
如果对你有帮助的话,还请关注点赞收藏⭐评论哦
不定时回访哟