全局配置
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設置默認值
關於fromData傳參(通常用於上傳文件,圖片等)
因爲axios默認發送數據時,數據格式是Request Payload,而並不是咱們經常使用的Form Data格式,PHP後端未必能正常獲取到,因此有時咱們須要改用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.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解決跨域問題
一、下載proxy包:npm i http-proxy-middleware -S
二、全局搜素webpackDevServer.config.js 或直接找config/webpackDevServer.config.js 頁面
//proxy, //將以前的註釋掉
proxy:{ //加入這段代碼
"/zzzzz":{ //命名隨意
"target":"http://106.12.52.123:8080",
"changeOrigin":true,
pathRewrite:{
"^/zzzzz":""
}
}
},
三、src/api/config.js頁面
module.exports={
//base:"http://106.12.52.123:8080" //去除此行代碼
base:"/zzzzz" //增長此行代碼
}
四、package.json
"proxy":"http://106.12.52.123:8080", //能夠不加
五、接口寫法
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("服務器出錯")
})
},
六、從新啓動(必要的,切記每次改動proxy都應該重啓項目)
原理:請求接口:請求地址 --> 拋給proxy -->proxy處理跨域請求 -->完成
proxy扮演一個代理的角色,您不能處理跨域問題,但他能夠,因此你把請求發給他,他幫你處理。