全局配置
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设置默认值
由于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扮演一个代理的角色,您不能处理跨域问题,但他可以,所以你把请求发给他,他帮你处理。