后端程序员入门react笔记(五)ajax请求

常见的ajax

  • Ajax
    最原始的方式,基于原生的js

  • XmlHttpRequest
    多个请求之间如果有先后关系,会存在很多层回调的问题,也是基于原生js

  • Jquery Ajax
    基于原生XHR封装,依赖Jquery框架,由jquery 框架去封装原生的XML(Xml)封装的API,支持JSONP,如果只是用于发送Ajax而使用jQuery,不推荐。

  • Fetch
    Fetch是一种HTTP数据请求的方式,是XMLHttpRequest的一种替代方案。Fetch不是ajax的进一步封装,它们是两个东西。Fetch函数就是原生js,和XMLHttpRequest是同级别的原生js的api,Fetch 的出现就是为了解决 XHR 的问题,它实现了 Promise 规范,返回 Promise 实例;而 Promise 是为解决异步回调问题而摸索出的一套方案。

  • axios
    对原生XHR的封装,需要进行安装,可以在客户端使用,也可以在node端使用,Axios 是一个基于 promise (Promise 是异步编程的一种解决方案)的 HTTP 库,可以用在浏览器和 node.js 中。

Axios

接下来我们重点了解一下axios

特性

  • 可以从浏览器中创建 XMLHttpRequests
  • 可以从 node.js 创建 http 请求
  • 支持 Promise API
  • 可以拦截请求和响应
  • 可以转换请求数据和响应数据
  • 可以取消请求
  • 自动转换 JSON 数据
  • 客户端支持防御 XSRF

基本使用

我们只需要在组件中引入axios组件即可使用,我们简单举个列子看一下,请求响应的处理在 then 和 catch 回调中,请求正常会进入 then ,请求异常则会进 catch

import React, {Component} from 'react';
//引入组件
import axios from 'axios';class App extends Component {getData = () => {//发送请求   请求响应的处理在 then 和 catch 回调中,请求正常会进入 then ,请求异常则会进 catchaxios.get('http://localhost/data').then((res) => {console.log(res);}).catch((err) => {console.log(err);})}render() {return (<button onClick={this.getData}> 点击获取数据</button>);}
}
export default App;

发送请求的两种方式

axios提供了两种方式来发送请求, 一种是通过axios(config)来发送请求,另一种就是上面列子中的axios.get,

axios(config)

config是一个对象,里面配置了请求相关的信息,比如下面这个例子

        axios({//请求方法method: 'post',//请求urlurl: '/user/12345',//请求参数data: {firstName: 'Fred',lastName: 'Flintstone'}}).then(res=>{//请求成功console.log(res);}).catch(err=>{//请求失败console.log(err);})
  • config可配置的相关项
    config里面可以配置代理,超时,相应的最大尺寸,是否重定向等等
{// `url` 是用于请求的服务器 URLurl: '/user',// `method` 是创建请求时使用的方法method: 'get', // default// `baseURL` 将自动加在 `url` 前面,除非 `url` 是一个绝对 URL。// 它可以通过设置一个 `baseURL` 便于为 axios 实例的方法传递相对 URLbaseURL: 'https://some-domain.com/api/',// `transformRequest` 允许在向服务器发送前,修改请求数据// 只能用在 'PUT', 'POST' 和 'PATCH' 这几个请求方法// 后面数组中的函数必须返回一个字符串,或 ArrayBuffer,或 StreamtransformRequest: [function (data, headers) {// 对 data 进行任意转换处理return data;}],// `transformResponse` 在传递给 then/catch 前,允许修改响应数据transformResponse: [function (data) {// 对 data 进行任意转换处理return data;}],// `headers` 是即将被发送的自定义请求头headers: {'X-Requested-With': 'XMLHttpRequest'},// `params` 是即将与请求一起发送的 URL 参数// 必须是一个无格式对象(plain object)或 URLSearchParams 对象params: {ID: 12345},// `paramsSerializer` 是一个负责 `params` 序列化的函数// (e.g. https://www.npmjs.com/package/qs, http://api.jquery.com/jquery.param/)paramsSerializer: function(params) {return Qs.stringify(params, {arrayFormat: 'brackets'})},// `data` 是作为请求主体被发送的数据// 只适用于这些请求方法 'PUT', 'POST', 和 'PATCH'// 在没有设置 `transformRequest` 时,必须是以下类型之一:// - string, plain object, ArrayBuffer, ArrayBufferView, URLSearchParams// - 浏览器专属:FormData, File, Blob// - Node 专属: Streamdata: {firstName: 'Fred'},// `timeout` 指定请求超时的毫秒数(0 表示无超时时间)// 如果请求话费了超过 `timeout` 的时间,请求将被中断timeout: 1000,// `withCredentials` 表示跨域请求时是否需要使用凭证withCredentials: false, // default// `adapter` 允许自定义处理请求,以使测试更轻松// 返回一个 promise 并应用一个有效的响应 (查阅 [response docs](#response-api)).adapter: function (config) {/* ... */},// `auth` 表示应该使用 HTTP 基础验证,并提供凭据// 这将设置一个 `Authorization` 头,覆写掉现有的任意使用 `headers` 设置的自定义 `Authorization`头auth: {username: 'janedoe',password: 's00pers3cret'},// `responseType` 表示服务器响应的数据类型,可以是 'arraybuffer', 'blob', 'document', 'json', 'text', 'stream'responseType: 'json', // default// `responseEncoding` indicates encoding to use for decoding responses// Note: Ignored for `responseType` of 'stream' or client-side requestsresponseEncoding: 'utf8', // default// `xsrfCookieName` 是用作 xsrf token 的值的cookie的名称xsrfCookieName: 'XSRF-TOKEN', // default// `xsrfHeaderName` is the name of the http header that carries the xsrf token valuexsrfHeaderName: 'X-XSRF-TOKEN', // default// `onUploadProgress` 允许为上传处理进度事件onUploadProgress: function (progressEvent) {// Do whatever you want with the native progress event},// `onDownloadProgress` 允许为下载处理进度事件onDownloadProgress: function (progressEvent) {// 对原生进度事件的处理},// `maxContentLength` 定义允许的响应内容的最大尺寸maxContentLength: 2000,// `validateStatus` 定义对于给定的HTTP 响应状态码是 resolve 或 reject  promise 。如果 `validateStatus` 返回 `true` (或者设置为 `null` 或 `undefined`),promise 将被 resolve; 否则,promise 将被 rejectevalidateStatus: function (status) {return status >= 200 && status < 300; // default},// `maxRedirects` 定义在 node.js 中 follow 的最大重定向数目// 如果设置为0,将不会 follow 任何重定向maxRedirects: 5, // default// `socketPath` defines a UNIX Socket to be used in node.js.// e.g. '/var/run/docker.sock' to send requests to the docker daemon.// Only either `socketPath` or `proxy` can be specified.// If both are specified, `socketPath` is used.socketPath: null, // default// `httpAgent` 和 `httpsAgent` 分别在 node.js 中用于定义在执行 http 和 https 时使用的自定义代理。允许像这样配置选项:// `keepAlive` 默认没有启用httpAgent: new http.Agent({ keepAlive: true }),httpsAgent: new https.Agent({ keepAlive: true }),// 'proxy' 定义代理服务器的主机名称和端口// `auth` 表示 HTTP 基础验证应当用于连接代理,并提供凭据// 这将会设置一个 `Proxy-Authorization` 头,覆写掉已有的通过使用 `header` 设置的自定义 `Proxy-Authorization` 头。proxy: {host: '127.0.0.1',port: 9000,auth: {username: 'mikeymike',password: 'rapunz3l'}},// `cancelToken` 指定用于取消请求的 cancel token// (查看后面的 Cancellation 这节了解更多)cancelToken: new CancelToken(function (cancel) {})
}
  • 配置全局默认值
    我们可以给axios配置默认值
axios.defaults.baseURL = 'https://api.example.com';
axios.defaults.headers.common['Authorization'] = AUTH_TOKEN;
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
axios.option

我们也可以使用axios.get()这种方式发送请求,里面定义data和config

        axios.get('http://localhost/data').then().catch()axios.post('http://localhost/data',{name:'张三'},{timeout: 1000}).then().catch()

拦截器

axios提供了请求拦截器和响应拦截器,帮助我们在请求前对config做一些配置,判断是否重复提交,或者对config做一些检查以及配置纠正等,响应拦截器帮助我们根据不同的返回内容做不同的数据处理,相关案例如下

import React, {Component} from 'react';
//引入组件
import axios from 'axios';
// 创建一个请求拦截器 请求头附加一个token 值是1111
const requestInterceptor = axios.interceptors.request.use((config) => {config.headers['token'] = '1111111';return config;},(error) => {// 处理请求错误return Promise.reject(error);}
);
// 创建一个响应拦截器
const responseInterceptor = axios.interceptors.response.use((response) => {// 处理响应数据return response;},(error) => {console.log(error);// 处理响应错误return Promise.reject(error);}
);
class App extends Component {// 添加请求拦截器getData = () => {axios.post('http://localhost/data',{name:'张三'},{timeout: 1000}).then(res=>{console.log(res);},err=>{console.log(err);}).catch(err=>{console.log(err);})}render() {return (<button onClick={this.getData}> 点击获取数据</button>);}
}
// 移除拦截器
axios.interceptors.request.eject(requestInterceptor);
axios.interceptors.response.eject(responseInterceptor);
export default App;

开启后端服务,发送请求

我们知道,我们前端的服务器是3000端口,但是我们后端的服务器不一定是3000,也可能是80端口,现在我启动一个go编写的后台服务,调用一下接口
我这现在有一个获取博客详情的接口,端口号是8080
在这里插入图片描述
接下来我们通过axios访问一下

    getData = () => {axios.get('http://127.0.0.1:8080/v1/blog/detail?id=123').then(res=>{console.log(res);},err=>{console.log(err);}).catch(err=>{console.log(err);})}

问题来了,浏览器发送了请求,后端的gin服务收到了请求,但是结果没过来,浏览器报错说我跨域了。这说明主要问题在Ajax引擎对响应的处理那块。怎么办?作为后端人员最熟悉不过的方式就是做个代理。
在这里插入图片描述

配置代理

怎么配置代理呢?我们可以在react项目根目录下的package.json里面配置上这样一句声明,这表示请求的3000端口的请求会被转发到8080,对于后端人员都明白,这个转发规则是什么呢?优先匹配3000服务的路径,匹配不到再转去8080服务。

"proxy": "http://127.0.0.1:8080"
  • 把axios的请求改为本域名下路径就可以了
 axios.get('/v1/blog/detail?id=123')
  • 添加完毕后我们重启服务,响应数据回来了
    在这里插入图片描述
  • 但是上面这种有一个问题,就是不够灵活,比如我们常用的/blog/v1/detail需要代理到blog服务,但是我/goods/v1/detail是要代理到goods服务器。我们需要更灵活的配置方式,那么我们就需要借助一个第三方库http-proxy-middleware,接下来我们在src目录下新建一个setupProxy.js文件,内容如下
const {createProxyMiddleware} =require('http-proxy-middleware')
module.exports=function(app){app.use(createProxyMiddleware('/api',{ // api 是需要转发的请求(所有带/api 前缀的请求都会转发给8080)target:'http://localhost:8080', // 配置转发目标地址(能返回数据的服务器地址)changeOrigin:true, // 控制服务器接收到的请求头中host字段的值//设置为true,服务器端接收的host就是8080,如果为false,那么后端服务器接收到的host就是3000//  changeOrigin 默认值为false 但我们一般将changeOrigin值设为truepathRewrite:{'^/api':''} // 去请求前缀,保证交给后台服务器是正常请求地址(必须配置)}),)
}
  • 在发送请求的时候,如果是需要代理,我们只需要在原来的url上面加上/api/就可以了,或者和后端协商好某个统一前缀也能解决。
 axios.get('/api/v1/blog/detail?id=123')//被转发后就是/v1/blog/detail?id=123

案例一 用户搜索

静态页面渲染

  • index.js
import React from "react";
import ReactDOM  from "react-dom/client";
import App from "./App";
const content=<App/>
const root=ReactDOM.createRoot(document.getElementById("root"))
root.render(content)
  • app.jsx
import React, {Component} from 'react';
import Search from './components/Search/Search'
import List from "./components/List/List";class App extends Component {render() {return (<div><div className="container"><Search></Search><List></List></div></div>);}
}export default App;
  • Search.jsx
import React, {Component} from 'react';class Search extends Component {render() {return (<div><section className="jumbotron"><h3 className="jumbotron-heading">Search Github Users</h3><div><input type="text" placeholder="enter the name you search"/>&nbsp;<button>Search</button></div></section></div>);}
}export default Search;
  • list.jsx
import React, {Component} from 'react';
import './List.css'class List extends Component {render() {return (<div><div className="row"><div className="card"><a rel="noreferrer" href="https://github.com/reactjs" target="_blank"><img alt="head_protrait" src="https://avatars.githubusercontent.com/u/6412038?v=3" style={{width:'100px'}}/></a><p className="card-text">reactjs</p></div></div></div>);}
}export default List;

在这里插入图片描述

配置代理 获取数据

真实接口地址如下https://api.github.com/search/users?q=react,我们先拿到数据吧,点击search获取到input的内容,并尝试请求数据

  • Search.jsx
import React, {Component, createRef} from 'react';
import axios from "axios";class Search extends Component {searchInput=createRef()searchData=()=>{//获取input的值const key=this.searchInput.current.value//发送Ajax请求axios.get(`/api/search/users?q=${key}`).then(res=>{console.log(res);},(err)=>{console.log(err);}).catch(err=>{console.log(err);})//}render() {return (<div><section className="jumbotron"><h3 className="jumbotron-heading">Search Github Users</h3><div><input type="text" ref={this.searchInput} placeholder="enter the name you search"/>&nbsp;<button onClick={this.searchData}>Search</button></div></section></div>);}
}export default Search;
  • 点击搜索后我们发现一个问题,接口返回的和axios里面的结构不一致,可以看出,axios对接口数据又做了封装
    在这里插入图片描述

把数据传递给state,并渲染列表

  • list.jsx
class List extends Component {render() {const data=this.props.data;return (<div><div className="row">{data.map((item,index)=>{return  <div className="card" key={item.html_url}><a rel="noreferrer" href={item.html_url} target="_blank"><img alt="head_protrait" src={item.avatar_url} style={{width:'100px'}}/></a><p className="card-text">{item.login}</p></div>})}</div></div>);}
}
  • app.js
    getData=(data)=>{console.log(data);this.setState({list:data})}

在这里插入图片描述

发布订阅和同步机制

我们从上一个搜索的例子其实可以看到,在app search list组件直接传递数据的时候,我们都绕不开父组件app,那么有没有一种方式,让search 和list直接沟通,而不需要再通过父组件App传递? 这就用到了发布订阅。
其实后端同学都很熟悉发布订阅模式,首先我们需要创建一个topic,然后有发布者,还得有订阅者。
接下来我们使用第三方组件pubsubjs来体验一下发布订阅,

  • search.jsx
import React, {Component, createRef} from 'react';
import axios from "axios";
import PubSub from 'pubsub-js';class Search extends Component {searchInput=createRef()searchData=()=>{//获取input的值const key=this.searchInput.current.value//发送Ajax请求axios.get(`/api/search/users?q=${key}`).then(res=>{//发布消息PubSub.publish('list',res.data.items);},(err)=>{console.log(err);}).catch(err=>{console.log(err);})//}render() {return (<div><section className="jumbotron"><h3 className="jumbotron-heading">Search Github Users</h3><div><input type="text" ref={this.searchInput} placeholder="enter the name you search"/>&nbsp;<button onClick={this.searchData}>Search</button></div></section></div>);}
}export default Search;
  • list.jsx
import React, {Component} from 'react';
import './List.css'
import PubSub from 'pubsub-js';class List extends Component {state ={data:[]}getData = (msg, data) => {this.setState({data:data})}//挂载完毕开始订阅componentDidMount() {//用一个函数处理订阅消息const token= PubSub.subscribe('list', this.getData);this.setState({token:token})}//卸载后取消订阅componentWillUnmount() {PubSub.unsubscribe(this.state.token);}render() {const data=this.state.data;return (<div><div className="row">{data.map((item,index)=>{return  <div className="card" key={item.html_url}><a rel="noreferrer" href={item.html_url} target="_blank"><img alt="head_protrait" src={item.avatar_url} style={{width:'100px'}}/></a><p className="card-text">{item.login}</p></div>})}</div></div>);}
}
export default List;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/2812962.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

GaussDB SQL调优:选择合适的分布列

一、背景 GaussDB是华为公司倾力打造的自研企业级分布式关系型数据库&#xff0c;该产品具备企业级复杂事务混合负载能力&#xff0c;同时支持优异的分布式事务&#xff0c;同城跨AZ部署&#xff0c;数据0丢失&#xff0c;支持1000扩展能力&#xff0c;PB级海量存储等企业级数…

策略模式:封装行为策略,灵活切换实现多态业务逻辑

文章目录 一、引言二、应用场景三、模式定义与实现四、优缺点分析总结 一、引言 ​ 策略模式&#xff08;Strategy Pattern&#xff09;是一种行为型设计模式&#xff0c;它定义了算法族&#xff0c;并分别封装起来&#xff0c;让它们之间可以互相替换。这种模式使得算法的变化…

Java+SpringBoot+Vue+MySQL构建银行客户管理新平台

✍✍计算机毕业编程指导师 ⭐⭐个人介绍&#xff1a;自己非常喜欢研究技术问题&#xff01;专业做Java、Python、微信小程序、安卓、大数据、爬虫、Golang、大屏等实战项目。 ⛽⛽实战项目&#xff1a;有源码或者技术上的问题欢迎在评论区一起讨论交流&#xff01; ⚡⚡ Java、…

电感电流波形分析

电感电流波形分析 首先&#xff0c;当电感充电时候&#xff08;红色回路&#xff09;电感左右两端是左正右负 假设在初始状态下&#xff0c;电容两端电压是0V&#xff0c;可以看出来A点电位是400V&#xff0c;B和C两端电容也都是0V 根据电感表达式di/dtUL/L400V/L 所以看得出…

【OnlyOffice】 桌面应用编辑器,版本8.0已发布,PDF表单、RTL支持、Moodle集成、本地界面主题

ONLYOFFICE桌面编辑器v8.0是一款功能强大、易于使用的办公软件&#xff0c;适用于个人用户、企业团队和教育机构&#xff0c;帮助他们高效地处理文档工作并实现协作。无论是在Windows、macOS还是Linux平台上&#xff0c;ONLYOFFICE都能提供无缝的编辑和共享体验。 目录 ONLYOFF…

华为高级路由技术 2023-2024

2023-2024 一、2.26路由协议版本优先级和度量主和备路由最长匹配原则递归路由和默认路由 一、2.26 路由协议版本 &#xff08;1&#xff09;RIP&#xff1a; IPv4网&#xff1a;RIPv1&#xff0c;RIPv2&#xff08;v1和v2 不兼容&#xff09; IPv6网&#xff1a;RIPng(Next g…

【网站项目】475商城系统

&#x1f64a;作者简介&#xff1a;拥有多年开发工作经验&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的项目或者毕业设计。 代码可以私聊博主获取。&#x1f339;赠送计算机毕业设计600个选题excel文件&#xff0c;帮助大学选题。赠送开题报告模板&#xff…

羊大师解读,羊奶都拥有哪些特点?

羊大师解读&#xff0c;羊奶都拥有哪些特点&#xff1f; 羊奶除了上述提到的丰富营养成分和健康优势外&#xff0c;还有以下一些特点&#xff1a; 接近母乳&#xff1a;羊奶的分子结构与母乳非常相似&#xff0c;特别是其含有大量的乳清蛋白&#xff0c;这使得羊奶成为婴儿和…

动态规划课堂2-----路径问题

目录 引言&#xff1a; 例题1&#xff1a;不同路径 例题2&#xff1a;不同路径II 例题3&#xff1a;礼物的最⼤价值 例题4&#xff1a;下降路径最⼩和 例题5&#xff1a;最小路径和 结语&#xff1a; 引言&#xff1a; 在学习完动态规划斐波那契数列模型后&#xff0c;…

【正式成立】工业互联网甄选联盟

工业互联网甄选联盟 联盟文件&#xff08;PDF&#xff09;&#xff1a;下载链接&#xff0c;提取码&#xff1a;m5d7 依托将近20年工业领域的智能制造相关项目实施经验、管理经验和产品开发经验&#xff1b;依托iNeuOS工业互联网操作系统、人工智能物流系统、MES制造执行系统等…

动态规划-最长公共子串(c)

动态规划 动态规划&#xff08;dynamic programming&#xff09;是一种算法设计方法。基本思想是在对一个问题的多阶段决策中&#xff0c;按照某一顺序&#xff0c;根据每一步所选决策的不同&#xff0c;会引起状态的转移&#xff0c;最后会在变化的状态中获取到一个决策序列。…

pdf如何压缩文件大小?pdf文件在线压缩方法介绍

在日常工作中&#xff0c;我们经常使用PDF文件进行传输和保存&#xff0c;然而&#xff0c;有时候我们会遇到过大的PDF文件&#xff0c;这不仅会导致传输困难&#xff0c;还会占用过多的设备空间&#xff0c;因此&#xff0c;我们需要对PDF压缩一下以便更轻松地传输和保存&…

2024年【安全员-B证】考试资料及安全员-B证模拟考试

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 安全员-B证考试资料是安全生产模拟考试一点通总题库中生成的一套安全员-B证模拟考试&#xff0c;安全生产模拟考试一点通上安全员-B证作业手机同步练习。2024年【安全员-B证】考试资料及安全员-B证模拟考试 1、【多选…

WebFilter【通过过滤器实现登录判断】

WebFilter【通过过滤器实现登录判断】 /*** 检查用户是否已经完成登录*/ WebFilter(filterName "loginCheckFilter",urlPatterns "/*") Slf4j public class LoginCheckFilter implements Filter{//路径匹配器&#xff0c;支持通配符public static final …

MATLAB环境下基于变分贝叶斯的组织学病理图像颜色盲反卷积方法

图像盲反卷积问题仅根据模糊图像估计清晰图像和模糊核&#xff0c;也是一个欠定问题且求解更加困难。但图像盲反卷积算法更实际&#xff0c;因为许多情况下&#xff0c;模糊核都是未知或部分已知的。求解盲反卷积问题需要为未知量选择适当的先验模型&#xff0c;以得到清晰图像…

SM100-40-080-P0-45-S1-B电机厦门参详

SM100-40-080-P0-45-S1-B交流伺服电机也是无刷电机&#xff0c;分为同步和异步电机&#xff0c;运动控制中一般都用同步电机&#xff0c;它的功率范围大&#xff0c;可以做到很大的功率。大惯量&#xff0c;最高转动速度低&#xff0c;且随着功率增大而快速降低。因而适合做低速…

JSON简介以及如何在Python中使用JSON

什么是JSON&#xff1f; JSON是"JavaScript Object Notation"的简称&#xff0c;是一种数据交换格式 JSON格式 假设我们有一个对象&#xff0c;这个对象有两个属性&#xff1a;“name”跟“age”。 在JSON中是这样表达的&#xff1a; { "name":"男孩…

APP软件设计要注意的问题

设计一个成功的APP软件需要考虑多个方面&#xff0c;成功的APP设计需要综合考虑用户体验、性能稳定性、安全性、兼容性、反馈机制、内容质量和法律合规等多个方面&#xff0c;不断优化和改进以满足用户需求并提升用户满意度。以下是一些需要注意的问题&#xff0c;希望对大家有…

免费的通配符(泛域名证书)?

通配符证书&#xff08;Wildcard SSL Certificate&#xff09;是一种SSL证书&#xff0c;它可以用于保护一个域名及其所有的子域名。与传统的SSL证书不同&#xff0c;传统SSL证书仅用于保护一个单独的完全限定域名或一个子域名。通配符证书通过在域名前加上一个星号&#xff08…

VUE从0到1创建项目及基本路由、页面配置

一、创建项目:(前提已经安装好vue和npm) 目录:E:\personal\project_pro\ windows下,win+R 输入cmd进入命令行: cd E:\personal\project_pro E:# 创建名为test的项目 vue create test# 用上下键选择vue2或vue3,回车确认创建本次选择VUE3 创建好项目后,使用…