文章目录

  • 🍩React ajax
  • 🍧前置小知识
  • 🍰说明
  • 🧁常用的ajax请求库
  • 🍬使用axios发送请求
  • 📛问题
  • 🧃如何开启代理服务器?
  • 🧃如何配置多个代理服务器?


🍩React ajax

在之前的一篇文章中,详细介绍了解决跨域的两种方式,今天主要讲在react脚手架中发送Ajax请求解决跨域的另外两种代理方式,有需要的话可以耐心看完哦🥰

react express 跨域 react跨域请求_javascript

🍧前置小知识

🍰说明

  1. React本身只关注于界面, 并不包含发送ajax请求的代码
  2. 前端应用需要通过ajax请求与后台进行交互(json数据)
  3. react应用中需要集成第三方ajax库(或自己封装)

🧁常用的ajax请求库

  1. jQuery: 比较重, 如果需要另外引入不建议使用
  2. axios: 轻量级, 建议使用
  • 封装XmlHttpRequest对象的ajax
  • promise风格
  • 可以用在浏览器端和node服务器端

🍬使用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按下回车键,查看服务是否可以成功返回数据:

react express 跨域 react跨域请求_代理模式_02

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>
);
}
}

当点击按钮时,控制台显示报错:

react express 跨域 react跨域请求_ajax_03

📛问题

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。(代理好比中介)

react express 跨域 react跨域请求_javascript_04

🧃如何开启代理服务器?

方法一(最简单):

package.json中加一行代码(如下图),意思是:代理给5000端口的地址发送请求。

然后原先axios给5000端口号发送请求,需要改为3000端口号,因为代理的端口号是3000。

react express 跨域 react跨域请求_ajax_05

getStudentData = () => {
    axios.get('http://localhost:3000/students').then(
      response => { console.log('成功了', response.data) },
      error => { console.log('失败了', error) }
    )
  }

运行结果:

react express 跨域 react跨域请求_javascript_06

那么问题来了?axios所有的请求都转发给5000端口吗?答案:不是。

3000端口有的资源,代理服务器就不会转发给5000端口了,如果当请求了3000不存在的资源时,那么该请求会转发给5000。

总结说明:

  1. 优点:配置简单,前端请求资源时可以不加任何前缀。
  2. 缺点:不能配置多个代理。
  3. 工作方式:上述方式配置代理,当请求了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替换成一个空字符串,去除请求前缀,保证交给后台服务器的是正常请求地址。

说明:

  1. 优点:可以配置多个代理,可以灵活的控制请求是否走代理。
  2. 缺点:配置繁琐,前端请求资源时必须加前缀。

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>
    );
  }
}

💿总体效果:

react express 跨域 react跨域请求_react express 跨域_07