• react前后端对接(axios)


    全局配置

    1  安装axios     npm install axios -S   
    
    2  安装cookie    npm install react-cookies -S
    
    3  src文件目录下新建文件夹api
    
    4  api 下新建statecode.js  //该页面用来返回请求状态
    export default  {
        "-1": "系统繁忙",
        "0": "请求成功",
        "1001":	"资源已存在",
        "1002":	"参数错误",
        "1003":	"两次密码不一致",
        "1004":	"手机号错误",
        "1005":	"邮箱格式错误",
    }
    
    5  api下新建config.js    //该页面用来设置请求地址
    module.exports = {
        base: "http://demo.port.net:8000"
    };
    
    6 api下新建index.js   //该页面用来引入并暴露相关接口,相当于接口汇总(每配置一个模块的接口,都要在这里汇总,别忘了)
    import codes from './statecode.js';   //状态码
    import login from './login.js';    //登录页面
    import product from './product.js';   //产品页面
    import buy from './buy.js';  //购买页面
     
    export default {
        stateCode: codes,
        ...login,
        ...product,
        ...buy,
    }
    
    7  api下新建login.js, product.js, buy.js等相关模块的接口页面(这里给post,get,delete等每种请求写一个例子)
    import axios from 'axios';  //引入axios
    import { base } from "./config.js";  //引入请求地址
    import cookie from 'react-cookies';//引入cookie保存登录信息
    
    import {message} from 'antd';
    
    export default {
    
            //***登录 (POST)*** 
            async loginApi(params){   //我习惯在接口命名时,后面加上Api,这样容易区分
                return await axios.post(`${base}/api/demo/login`,params).then((res)=>{  //登录接口不需要请求头,不仅如此,请求头里的cookie还是由登陆接口的获取的,存储下来后给其他接口使用
                    return res.data;
                }).catch((error)=>{
                    message.error("服务器出错")
                })
            },
    
    
            //***登录后获取用户信息 (GET)***
            async getUserInfoApi(params){
                return await axios.get(`${base}/api/demo/info`,{   //get请求只需要两个参数,所以params和headers放在了一起
                    params,
                    headers:{
                        "token":cookie.load("usertoken")   //这里的cookie需要在用户登陆后,将接口的返回值存进cookie里,例子在第8步里
                    }
                }).then((res)=>{
                    return res.data;
                }).catch((error)=>{
                    message.error("服务器出错")
                })
            },
    
            //***修改密码 (POST)***
            async changePasswordApi(params){
                return await axios.post(`${base}/api/demo/modifycode`,params,{
                    headers:{
                        "token":cookie.load("usertoken")
                    }
                }).then((res)=>{
                    return res.data;
                }).catch((error)=>{
                    message.error("服务器出错")
                })
            },
    
            //***获取产品列表 (GET)***
            async productListGetApi(params){
                return await axios.get(`${base}/api/product`,{
                    params,
                    headers:{
                        "token":cookie.load("usertoken")
                     }
                }).then((res)=>{
                    return res.data
                }).catch((error)=>{
                    message.error("服务器出错")
                })
            },
        
            //***删除产品 (DELETE) ***
            async productDeleteApi(params){
                return await axios.delete(`${base}/api/product/${params.id}`,{   //删除接口需要获取当前数据的id才可进行删除
                    params,
                    headers:{
                        "token":cookie.load("usertoken"),
                    }
                }).then((res)=>{
                    return res.data
                }).catch((error)=>{
                    message.error("服务器出错")
                })
            }
    
            //***修改产品信息 (PUT)***
            async productModify(params){
                return await axios.put(`${base}/api/demo/product/${localStorage.getItem("listid")}/${params.id}`, params,{
                    headers:{
                        "token":cookie.load("usertoken")
                    }
                }).then((res)=>{
                    return res.data;
                });
            },
        
    }
    
    
    
    8 在相关页面对接口
        import api from '../../api/index.js';  //引入接口文档
        import cookie from 'react-cookies'  //在登录页面需要引入cookie用来存储登录信息,其他页面不需要
        
        state={
    
            //登录接口所需参数
            loginpost:{
                username:"",
                password:"",
                code:"",
            },
    
            //用户信息
            userNickname:"",
    
            //修改密码接口所需参数
            changePasswordFile:{
                password:"",
                newPass:"",
                repeatPass:"",
                code:"",
            }
    
            
    
             //获取产品列表接口需要的参数
             pluginListFile:{
                 isloading:false,
                 name:"",
                 total:0,
                 page:1,
                 pageSize:20,
             },
             productList:[],  //从接口获取到的产品数据    
    
        }
    
        //***登录接口***
        handleLogin=async()=>{
            let {state} =this;
            let {username,password,code}=state.loginpost;
            let data=await api.loginApi({     //这个data是请求回来的数据
                username,    //这里是发送过去的参数
                password,
                code
            })
            if(data.code===0){
                cookie.save('usertoken', data.data)   //登录接口除了返回code,msg,还会返回一个字段(如这里的data)用来区分每一位用户,这里将接口返回的data,存储到cookie里即可
                message.success("登录成功!",3);
                this.userInfoGet();   //登录后调用“获取用户信息接口”来获取相关信息如昵称,头像,渲染到页面上
            }else{
                console.log(api.stateCode[data.code])   //如果请求失败,在这里打印状态码告诉程序员错误原因
                return;
            }
        }
    
        //***获取用户信息接口***
        async userInfoGet(){
            let res=await api.getUserInfoApi()
            if(res.code===0){
                this.setState({
                    userNickname:res.data.nickname
                })
            }else{
                console.log(api.stateCode[res.code]);
            }
        }
    
        //***修改密码接口***
        passwordChange=async()=>{
            let {password,newPass,repeatPass,code} =this.state.changePasswordFile;
            let data=await api.changePasswordApi({  
                password,    
                newPass,
                repeatPass,
                code,
            })
            if(data.code===0){
                message.success("密码修改成功!")
                cookie.remove('usertoken')    //密码修改成功后,这里清除cookie,让用户重新登录
                this.setState({
                    userNickname:"",  //将用户昵称重新设为空并渲染到页面,让用户知道自己已登出
                })
            }else{
                console.log(api.stateCode[data.code]);
                return;
            }
        }
    
        //***获取产品列表接口***
        componentWillMount=async()=>{  //在页面渲染完毕之前就执行
            this.productListGet();
        }
        
        //***页码改变***
        onChangePage=(page=1,pageSize=20)=>{
            this.setState({
                productListFile:Object.assign(this.state.productListFile,{
                    page,pageSize
                })
            })
            this.productListGet();
        }
    
        async productListGet(){
            this.setState({
                productListFile:Object.assign(this.state.productListFile,{
                    isloading:true,
                })
            })
            let res=await api.productListGetApi(this.state.productListFile)
            this.setState({
                productListFile:Object.assign(this.state.productListFile,{
                    isloading:false
                })
            });
            if(res.code===0){
                this.state.productList=res.data.data;
                this.state.productListFile.total=res.data.total;
            }else{
                console.log(api.stateCode[res.code]);
            }
            this.setState(this.state);   //再获取到数据后,重新渲染页面将数据展示出来
        }
    
        //***删除产品接口***
        productDelete=async(productList)=>{
            let data=await api.productDeleteApi({
                id:productList.id,
            })
            if(data.code===0){
                this.onChangePage();
                message.success(`插件${productList.name}删除成功!`)
            }else{
                message.error(api.stateCode[data.code])
            }
        }
    
        //***修改产品信息***
        modifyProduct=async()=>{
            let {name,keyword}=this.state;
            let data = await api.productModify({
                id:state.qproductmsg.id,     //因为是修改已经获取到的信息,所以直接调用前面已经获取到的qrcodemsg即可
                name,
                keyword,
            })
            if(data.code===0){
                message.success('关键二维码修改成功', 3,);
                this.props.history.goBack();
            }else{
                console.log(api.stateCode[data.code]);
                return;
            }
    
    
     }
    

    读懂接口文档

    
    /api/wechat/qrcode/:officialId/:qrcodeId  带冒号,动态数据:`${base}/api/wechat/qrcode/${localStorage.getItem("listid")}/${params.id}`  //这列的:qrcodeId需要使用${params.id}动态写入,params即数组
    /api/wechat/statistics/:officialId/qrcode  不带冒号,静态的:`${base}/api/wechat/statistics/${localStorage.getItem("listid")}/qrcode`  //这里的qrcode直接写上去就可以
     
    

    参数问题

      request<T = any>(config: AxiosRequestConfig): AxiosPromise<T>;   //request 一个参数  config
      get<T = any>(url: string, config?: AxiosRequestConfig): AxiosPromise<T>;  //get  两个参数 url config
      delete(url: string, config?: AxiosRequestConfig): AxiosPromise;  //delete  两个参数  url config
      head(url: string, config?: AxiosRequestConfig): AxiosPromise;   //head  两个参数 url config
      post<T = any>(url: string, data?: any, config?: AxiosRequestConfig): AxiosPromise<T>;  //post 三个参数 url data config
      put<T = any>(url: string, data?: any, config?: AxiosRequestConfig): AxiosPromise<T>; // put 三个参数 url data config
      patch<T = any>(url: string, data?: any, config?: AxiosRequestConfig): AxiosPromise<T>; // patch 三个参数 url data config
    
    参数解释 :url —— 请求地址
                       data——发送给服务器的请求数据
                       config——配置(请求头等),一般都是固定格式
    
    举个栗子:
      export default{
            async codeDeisgn(params){                                                 
                    return await axios.put(`${base}/api/wechat/code/${localStorage.getItem("listid")}/${params.id}`, params,{  //url data
                              headers:{                         //config  一般都是固定格式
                                   "token":cookie.load("usertoken")
                              }
                    }).then((res)=>{
                          return res.data;
                    });
           },
            async qrcodeExtend(params){
            return axios.post(`${base}/api/wechat/code/${localStorage.getItem('listid')}/${params.id}/extend`,{},{   ////这里data就没有传参,而是用{}表示
                headers:{
                    "token":cookie.load("usertoken")
                }
            }).then((res)=>{
                return res.data;
            });
        },
      }
    注意:需要的参数,一个都不少,data如果不需要传,设置为{}都行,也不能不传
    
    

    受控组件和不受控组件

    在HTML中,<textarea> 的值是通过子属性设置的。在React中,需要通过value设置。我们可以通过添加事件属性onChange监听内容的变化,onChange会在下列情况下被触发:
    input或者textarea的内容改变
    input的checked状态改变
    select的状态改变
    
    【受控组件】
    设定了value的input就是一个受控组件。input里会一直展现这个值,用户的任何输入都是无效的。如果你想随着用户的输入改变,使用onChange事件,或者将value改为defaultValue
    
    【非受控组件】
    value没有值或者值设为null的input是一个不受控组件。用户的任何输入都会反映到输入框中
    这个时候也可以监听onChange事件,内容的改变也会触发事件。
    可以通过defaultValue给input设置默认值
    

    关于FormData传参(一般用于文件,图片上传以及登录注册等表单信息这种)

    由于axios默认发送数据时,数据格式是Request Payload,而并非我们常用的Form Data格式,后端未必能正常获取到,所以有时我们需要改用FormData方式发送数据
    未改用之前
    async postPersonInfo(params){
            return axios.post(`${base}/api/auth/realname`,params,{
                headers:{
                    "token":cookie.load("usertoken")
                }
            }).then((res)=>{
                return res.data;
            }).catch((error)=>{
                message.error("服务器错误")
            })
        }
    改用formData传数据
    async postPersonInfo(params){
            let formData = new FormData();  //以FormData的形式提交,注意FormData的首字母大写
            formData.append("name",params.id);
            formData.append("version",params.version);
            formData.append('idcard',params.idcard);  
            formData.append('name',params.name);  
            return axios.post(`${base}/api/product/name`,formData,{
                headers:{
                    "token":cookie.load("usertoken"),
                    'Content-Type':'multipart/form-data',    //设置类型
                }
            }).then((res)=>{
                return res.data;
            }).catch((error)=>{
                message.error("服务器错误")
            })
        }
    
    
    有时设置 withCredentials:true , 表示跨域请求时是否需要使用凭证. 默认为false
    authen(event) {
             event.preventDefault();
      
            let formData = new FormData();  
             formData.append('fileUpload1',this.files);  
             formData.append('fileUpload2',this.files2);  
             formData.append('fileUpload3',this.files3); 
             formData.append('uid',this.userID);
             formData.append('name',this.name);
    
            const instance=axios.create({
              withCredentials: true
             }) 
                  
            instance.post('http://pay.m6zf.com/index.php?s=/api/user/approved.html',formData).then(res=>{
               
                    if(res.code == 200){
                        alert('提交成功');
                         this.$router.push({ path: "/Profit" });
    
                    }else{
                        alert("请输入完整再提交");
                    }
    
                })    
         }
    
    详细见:https://www.jianshu.com/p/bcf19f69ee4f
    
    注:应用场景,只要是请求一般均可使用,但目前我所使用的情况是在写图片等文件相关接口的时候
    

    请求时加入时间戳

    确保了请求不会在它第一次被发送后即缓存,而是会在此方法每次被调用后重新创建和重发
    verifyImgGet=async()=>{
            this.setState({
                verifyImg:`${base}/api/verifycode/image?time=${new Date().getTime()}`
            })
        }
    
    者也可以加一个随机数:
    
    var url="check.jsp?num="+Math.random();
    
    

    利用proxy解决跨域问题

    1、下载proxy包:npm i http-proxy-middleware -S
    2、全局搜素webpackDevServer.config.js 或直接找config/webpackDevServer.config.js 页面
    
    //proxy,  //将之前的注释掉
        proxy:{    //加入这段代码
          "/zzzzz":{   //命名随意
            "target":"http://106.12.52.123:8080",
            "changeOrigin":true,
            pathRewrite:{
              "^/zzzzz":""
            }
          }
        },
    
    3、src/api/config.js页面
    
    module.exports={
        //base:"http://106.12.52.123:8080"   //去除此行代码
        base:"/zzzzz"     //增加此行代码
    }
    
    4、package.json
    
    "proxy":"http://106.12.52.123:8080",   //可以不加
    
    5、接口写法
    async productListGetApi(params){
                return await axios.get(`${base}/api/product`,{     //${base}即表示/zzzzz,而/zzzzz又在proxy里等价于http://106.12.52.123:8080
                    params,
                    headers:{
                        "token":cookie.load("usertoken")
                     }
                }).then((res)=>{
                    return res.data
                }).catch((error)=>{
                    message.error("服务器出错")
                })
            },
    
    6、重新启动(必要的,切记每次改动proxy都应该重启项目)
    
    原理:请求接口:请求地址  --> 抛给proxy  -->proxy处理跨域请求  -->完成  
    proxy扮演一个代理的角色,您不能处理跨域问题,但他可以,所以你把请求发给他,他帮你处理。
    
  • 相关阅读:
    Atitit RSA非对称加密原理与解决方案
    Atitit RSA非对称加密原理与解决方案
    atitit.错误:找不到或无法加载主类 的解决 v4 qa15.doc
    atitit.错误:找不到或无法加载主类 的解决 v4 qa15.doc
    Mac设置su root密码
    Window系统命令行调用控制面板程序
    Ubuntu 安装最新版nodejs
    python中time.strftime不支持中文,报错UnicodeEncodeError: 'locale' codec can't encode character 'u5e74' in position 2: encoding error
    字节跳动——IT技术工程师面试题
    HTTP状态码
  • 原文地址:https://www.cnblogs.com/huihuihero/p/10926228.html
Copyright © 2020-2023  润新知