8.7 网络请求 🎉
8.7 网络请求 🎉
Fetch 💎
Fetch 是一种通信协议,用于客户端和服务器之间的数据传输。它允许浏览器从服务器异步请求数据,而无需刷新整个页面
Fetch API 是一个基于 Promise 的 JavaScript API,用于使用 Fetch 协议进行网络请求。Fetch API 提供了一种更简洁的方式来处理HTTP请求,并提供了比 XMLHttpRequest 更强大和灵活的功能。Fetch API 还允许开发人员轻松地使用现代 JavaScript 语言特性,如箭头函数和 async/await
Fetch API 支持多种数据格式,包括 JSON、二进制数据、FormData 等。它还支持 CORS(跨源资源共享)以及请求和响应拦截
总之,Fetch API 是一种现代的、灵活的、易于使用的方式来进行网络请求,并且它已经被大多数现代浏览器所支持
Fetch API 的基本用法是使用 fetch() 函数来发起HTTP请求,并返回一个 Promise 对象。该 Promise 对象会在请求完成后解析响应数据,并在请求成功时返回一个 Response 对象,或在请求失败时返回一个 rejected 状态的 Promise 对象
import React, { useEffect } from 'react';
export default function App() {
useEffect(() => {
fetch("http://iwenwiki.com/api/blueberrypai/getIndexBanner.php")
.then(response => {
return response.json();
})
.then(data => {
console.log(data)
})
.catch(error => {
console.log(error)
})
}, [])
return (
<div>
<p>11</p>
</div>
)
}
GET请求 👻
Fetch 默认发送 GET 请求,属于快捷方式。当然我们也可以指定具体的请求方式
fetch("http://iwenwiki.com/api/blueberrypai/getIndexBanner.php", {
method: 'GET',
headers: {
'Content-Type': 'application/json'
}
}).then(res => res.json()).then(data => {
console.log(data)
}).catch(error => {
console.log(error)
})
可以通过在 fetch() 函数的第二个参数中指定请求选项来实现这些方法,例如请求头、参数、模式、缓存等
//传参
fetch("http://iwenwiki.com/api/blueberrypai/getSongInfo.php?song=mo", {
method: 'GET',
headers: {
'Content-Type': 'application/json'
}
}).then(res => res.json()).then(data => {
console.log(data)
}).catch(error => {
console.log(error)
})
POST请求 👻
除了基本的 GET 请求外,Fetch API 还支持其他HTTP方法,如 POST、PUT 和 DELETE。可以通过在 fetch() 函数的第二个参数中指定请求选项来实现这些方法,例如请求头、请求体、模式、缓存等
fetch("http://iwenwiki.com/api/blueberrypai/login.php", {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body:"user_id=iwen@qq.com&password=iwen123&verification_code=crfvw"
}).then(res => res.json()).then(data => {
console.log(data)
}).catch(error => {
console.log(error)
})
将参数通过对象方式传递
我们可以借助 querystring 实现参数的格式转换
npm install --save querystring
import qs from "querystring"
fetch("http://iwenwiki.com/api/blueberrypai/login.php", {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: qs.stringify({
user_id: "iwen@qq.com",
password: "iwen123",
verification_code: "crfvw"
})
}).then(res => res.json()).then(data => {
console.log(data)
}).catch(error => {
console.log(error)
})
Fetch await 语法改写 👻
fetch() 使用 Promise,不使用回调函数,因此大大简化了写法,写起来更简洁
Promise 可以使用 await 语法改写,使得语义更清晰
// 定义网络请求函数
const fetchGET = async (url) =>{
const response = await fetch(url)
const result = await response.json()
return result
}
// 获取网络请求数据
const result = fetchGET("http://iwenwiki.com/api/blueberrypai/getIndexBanner.php")
result.then(res =>{
console.log(res)
})
Fetch取消请求 👻
fetch()请求发送以后,如果中途想要取消,需要使用AbortController对象
controller.abort()
方法用于发出取消信号
let controller = new AbortController();
fetch("http://iwenwiki.com/api/blueberrypai/getIndexBanner.php", {
method: 'GET',
headers: {
'Content-Type': 'application/json'
},
signal:controller.signal
}).then(res => res.json()).then(data => {
console.log(data)
}).catch(error => {
console.log(error)
})
controller.abort(); // 取消
在一定时间内取消网路请求
let controller = new AbortController();
setTimeout(() => controller.abort(), 10);
fetch("http://iwenwiki.com/api/blueberrypai/getIndexBanner.php", {
method: 'GET',
headers: {
'Content-Type': 'application/json'
},
signal:controller.signal
}).then(res => res.json()).then(data => {
console.log(data)
}).catch(error => {
console.log(error)
})
React跨域配置 💎
在开发模式下,如果客户端所在服务器跟后台服务器的地址或者端口不一致,则会出现跨域的问题
- 方式1:使用Proxy解决跨域
在package.json中设置Proxy属性:
"proxy":"http://localhost:3030"
设置代理后,则发送的api请求会被代理服务器转发到 localhost:3030
提示
proxy代理仅在开发中有效。
在生产环境下,这个代理无效
- 方式2:使用http-proxy-middleware
安装http-proxy-middleware
npm install http-proxy-middleware --save-dev
创建src/setupProxy.js文件(名字必须是这个名字,连后缀都不能变)
const { createProxyMiddleware } = require("http-proxy-middleware")
module.exports = function (app) {
app.use("/api", createProxyMiddleware({
target: "http://localhost:3005",
changeOrigin: true,
pathRewrite: {
'^/api': ''
}
}))
//可以代理多个
// app.use("/api1", createProxyMiddleware({
// target: "http://localhost:3005",
// changeOrigin: true,
// pathRewrite: {
// '^/api': ''
// }
// }))
}
Axios 💎
Axios 是一个基于 promise 的网络请求库,可以用于浏览器和 node.js
特性
- 从浏览器创建 XMLHttpRequests
- 从 node.js 创建 http请求
- 支持 Promise API
- 拦截请求和响应
- 转换请求和响应数据
- 取消请求
- 自动转换JSON数据
- 客户端支持防御XSRF
Axios 和 Fetch 的区别
- Axios 支持更广泛的浏览器和环境,包括浏览器、Node.js 等;而 Fetch 只能在现代浏览器中使用,需要额外的 polyfill 才能在旧版浏览器中使用
- Axios 可以自动地将响应数据转换为 JSON 格式,而 Fetch 不会自动转换,需要手动调用 response.json() 方法
- Axios 支持请求和响应的拦截器(interceptors),可以在请求发送前或响应返回后进行一些操作,例如添加公共请求头、响应异常处理等;而 Fetch 不支持拦截器
- Axios 支持取消请求,可以在请求还未返回时取消请求;而 Fetch 不支持取消请求
- Axios 在处理错误时更加友好,返回的错误信息更加详细和有用;而 Fetch 的错误信息相对较少
安装axios
npm instal axios --save
基本用例
axios("http://iwenwiki.com/api/blueberrypai/getIndexBanner.php").then(res =>{
console.log(res.data)
}).catch(error =>{
console.log(error)
})
GET请求 👻
执行 GET 请求,Axios提供可快捷方案
axios.get('http://iwenwiki.com/api/blueberrypai/getIndexBanner.php').then((response) => {
console.log(response.data);
}).catch(function (error) {
console.log(error);
});
GET传递参数
axios.get('http://iwenwiki.com/api/blueberrypai/getSongInfo.php?song=mo').then((response) => {
console.log(response.data);
}).catch(function (error) {
console.log(error);
});
增加配置信息,用对象方式传递参数
axios.get('http://iwenwiki.com/api/blueberrypai/getSongInfo.php', {
params: {
song: "mo"
}
}).then((response) => {
console.log(response.data);
}).catch(function (error) {
console.log(error);
});
POST请求 👻
执行 POST 请求,Axios提供可快捷方案
Axios POST 接收的网络请求参数需要进行格式转化
需求的格式 username=iwen
npm install --save querystring
import qs from "querystring"
axios.post("http://iwenwiki.com/api/blueberrypai/login.php", qs.stringify({
user_id: "iwen@qq.com",
password: "iwen123",
verification_code: "crfvw"
})).then(res =>{
console.log(res.data)
}).catch(error =>{
console.log(error)
})
并发请求 👻
在真实场景中,有可能会需要一次性获取多个网络请求的结果
处理并发请求的助手函数
- axios.all(iterable)
- axios.spread(callback)
function getBanner(){
return axios.get("http://iwenwiki.com/api/blueberrypai/getIndexBanner.php")
}
function getChating(){
return axios.get("http://iwenwiki.com/api/blueberrypai/getIndexChating.php")
}
const clickAllHandler = () =>{
axios.all([getBanner(),getChating()])
.then(axios.spread((banner,chating) =>{ // 两个参数分别代表两次网络请求的结果
console.log(banner.data,chating.data)
}))
}
Axios 封装 👻
封装 axios 之后,在使用上会更优雅,我们知道面向对象编程(OOP)遵循,低耦合高内聚。我们把网络请求放在一起更利于后期维护
新建/src/api/request.tsx
import axios from "axios"
const errorHandle = (status: any, info: any) => {
switch (status) {
case 400:
console.log("语义错误");
break;
case 401:
console.log("服务器认证失败");
break;
case 403:
console.log("服务器请求拒绝执行");
break;
case 404:
console.log("请检查网路请求地址");
break;
case 500:
console.log("服务器发生意外");
break;
case 502:
console.log("服务器无响应");
break;
default:
console.log(info);
break;
}
}
const instance = axios.create({
timeout: 50000,
})
const headers = {
"Content-Type": 'application/json',
"Authorization": 'lcl',
}
// 拦截器:请求拦截
instance.interceptors.request.use(
(config) => {
config.headers = headers
return config
},
(error) => Promise.reject(error)
)
// 拦截器:响应拦截
instance.interceptors.response.use(
(response) => response.status === 200 ? Promise.resolve(response) : Promise.reject(response),
(error) => {
const { response } = error;
if (response) {
errorHandle(response.status, response.info)
} else {
console.log("网络请求被中断了");
}
}
)
export default instance
新建/src/api/index.tsx
import axios from "./request"
const base = {
baseUrl: "/api", //代理地址在setupProxy.js文件里
select: "/list",
selectSwiper: "/selectSwiper",
}
const api = {
select(params: any) { //post请求
return axios.post(base.baseUrl + base.select, { params })
},
selectSwiper(params: any) { //get请求
return axios.post(base.baseUrl + base.selectSwiper, params)
},
}
export default api
发送请求
import api from "./api/index"
api.selectSwiper({
name: "jikezc",
}).then((res: any) => {
console.log(res.data);
})