FormData的主要用途
- 将form表单元素的name与value进行组合,实现表单数据的序列化,从而减少表单元素的拼接,提高工作效率。
- 异步上传文件
一、创建一个FormData对象
- 创建一个空对象:
//通过FormData构造函数创建一个空对象
var formdata=new FormData();
//可以通过append()方法来追加数据
formdata.append("name","laotie");
//通过get方法对值进行读取
console.log(formdata.get("name"));//laotie
//通过set方法对值进行设置
formdata.set("name","laoliu");
console.log(formdata.get("name"));//laoliu
- 通过表单对FormData初始化
- 创建表单:
<form id="advForm">
<p>广告名称:<input type="text" name="advName" value="xixi"></p>
<p>广告类别:<select name="advType">
<option value="1">轮播图</option>
<option value="2">轮播图底部广告</option>
<option value="3">热门回收广告</option>
<option value="4">优品精选广告</option>
</select></p>
<p><input type="button" id="btn" value="添加"></p>
</form>
- 通过表单元素作为参数,实现对formData的初始化:
//获得表单按钮元素
var btn=document.querySelector("#btn"); //querySelector() 方法仅仅返回匹配指定选择器的第一个元素。
//为按钮添加点击事件
btn.onclick=function(){
//根据ID获得页面当中的form表单元素
var form=document.querySelector("#advForm");
//将获得的表单元素作为参数,对formData进行初始化
var **formdata** =new FormData(form);
//通过get方法获得name为advName元素的value值
console.log(formdata.get("advName"));//xixi
//通过get方法获得name为advType元素的value值
console.log(formdata.get("advType"));//1
}
二、操作方法
- 通过get(key)与getAll(key)来获取相对应的值
// 获取key为age的第一个值
formdata.get("age");
// 获取key为age的所有值,返回值为数组类型
formdata.getAll("age");
- 通过append(key,value)在数据末尾追加数据
//通过FormData构造函数创建一个空对象
var formdata=new FormData();
//通过append()方法在末尾追加key为name值为laoliu的数据
formdata.append("name","laoliu");
//通过append()方法在末尾追加key为name值为laoli的数据
formdata.append("name","laoli");
//通过append()方法在末尾追加key为name值为laotie的数据
formdata.append("name","laotie");
//通过get方法读取key为name的 第一个值
console.log(formdata.get("name"));//laoliu
//通过getAll方法读取key为name的所有值
console.log(formdata.getAll("name"));//["laoliu", "laoli", "laotie"]
- 通过set(key, value)来设置修改数据
key值不存在时,会自动添加相应的一条数据
//将存在的key为name的值修改为laoli
formdata.set("name","laoli");
- 通过has(key)来判断是否存在对应的key值
//判断是否包含key为name的数据
console.log(formdata.has("name"));//true
//判断是否包含key为age的数据
console.log(formdata.has("age"));//false
- 通过delete(key)可以删除数据
//删除key为name的值
formdata.delete("name");
console.log(formdata.get("name"));//null
三、通过XMLHttpRequest发送数据
- 创建表单:
<form id="advForm">
<p>广告名称:<input type="text" name="advName" value="xixi"></p>
<p>广告类别:<select name="advType">
<option value="1">轮播图</option>
<option value="2">轮播图底部广告</option>
<option value="3">热门回收广告</option>
<option value="4">优品精选广告</option>
</select></p>
<p>广告图片:<input type="file" name="advPic"></p>
<p>广告地址:<input type="text" name="advUrl"></p>
<p>广告排序:<input type="text" name="orderBy"></p>
<p><input type="button" id="btn" value="添加"></p>
</form>
- 发送数据:
var btn=document.querySelector("#btn");
btn.onclick=function(){
var formdata=new FormData(document.getElementById("advForm"));
var xhr=new XMLHttpRequest();
xhr.open("post","http://127.0.0.1/adv");
xhr.send(formdata); // 上传文件
xhr.onload=function(){ // 请求成功回调函数
if(xhr.status==200){
//...
}
}
}
XMLHttpRequest知识详解 qs.stringify()将对象 序列化成URL的形式,以&进行拼接。
JSON是正常类型的JSON,请对比一下输出
Vue中axios的使用:
- get方法传递参数时需注意
axios.get('/data/json',{
params: {
id: 12
}
}).then(res => {
console.log(res);
})
status code: 304 not modified //请求到的数据与上次相同就会返回304 数据重定向
- post方法
常用的data格式:
- form-data 用于表单提交,图标与文件上传
- applicition/json
Content-Type:applicition/json //表示post方式以json格式发送 **Content-Type:multipart/from-data //表示post方式以formdata形式发送
post是新建 put与patch(只更新修改的)是更新
- delet方法
- 接口需要在url上拼接参数
axios.delete('/delete',{
params:{id: 12} //query string parameters
}).then()
- 不是在url上进行传输的
axios.delete('/delete',{
data:{id: 12} //request payload
}).then()
- 并发请求(同时进行多个请求,并统一处理返回值) axios.all()与axios.spread()
axios.all([ // 参数为一个数组
axios.get('/red'),
axios.get('/blue')
]).then(
axios.spread((redRes, blueRes) => {
console.log(redRes,blueRes);
})
);
二、axios配置
- 创建axios实例
let Axios = axios.create({
baseURL: 'http://127.0.0.1/read',
timeout: 5000
});
- axios的配置参数(config)
// `url` 是用于请求的服务器 URL,为相对路径,会在前面拼接baseURL
url: '/user',
// `method` 是创建请求时使用的方法
method: 'get', // default
// `baseURL` 将自动加在 `url` 前面,除非 `url` 是一个绝对 URL。
// 它可以通过设置一个 `baseURL` 便于为 axios 实例的方法传递相对 URL
baseURL: 'https://some-domain.com/api/',
// `headers` 是即将被发送的自定义请求头
headers: {
'X-Requested-With': 'XMLHttpRequest',
'token': ''
},
// `params` 是即将与请求一起发送的 URL 参数
// 必须是一个无格式对象(plain object)或 URLSearchParams 对象
params: {
ID: 12345
},
// `data` 是作为请求主体被发送的数据
// 只适用于这些请求方法 'PUT', 'POST', 和 'PATCH'
// 在没有设置 `transformRequest` 时,必须是以下类型之一:
// - string, plain object, ArrayBuffer, ArrayBufferView, URLSearchParams
// - 浏览器专属:FormData, File, Blob
// - Node 专属: Stream
data: {
firstName: 'Fred'
},
- 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';
- 实例配置
let instance = axios.create();
instance.defaults.timeout = 3000;
- 请求时配置
axios.get('/data.json', {
timeout: 5000
})
三、拦截器
在请求或响应被处理前拦截它们
- 请求拦截器
// 请求拦截器
axios.interceptors.request.use(
config => {
// 在发送请求前做些什么
// config.headers = {} // 不可以直接这样在请求拦截器里设置headers 这样会把实例上定义的其他headers && defauls上的headers配置 全部覆盖
config.headers.token = '' // 正确写法, headers里需要添加什么 再写什么
return config; //返回config
},
error => {
// 在请求错误的时候做些什么
return Promise.error(error); //返回一个promise对象
});
- 响应拦截器
axios.interceptors.response.use(
res => {
// 请求成功对响应数据做处理
return res
}, error => {
// 响应错误做什么
return Promise.reject(error)
}
);
- 取消拦截器
let interceptors = axios.interceptors.request.use(
config => {
// 在发送请求前做些什么
return config
},
error => {
// 请求错误的时候做什么
return Promise.reject(error)
}
);
// 取消拦截器
axios.interceptors.request.eject(interceptors);
- 拦截器应用举例
// 移动端应用
let interceptors_phone = axios.create();
interceptors_phone.interceptors.request.use(
config => {
$('#modal').show(); // model 表示显示加载的内容前的 等待
return config
}
);
interceptors_phone.interceptors.response.use(
res => {
$('#model').hide(); // 数据响应后隐藏model
return res
}
);
- 统一的错误处理
// 实际开发中,一般添加统一的错误处理,不会在每次请求后进行.catch的错误处理
let interceptors = axios.interceptors.request.use(
config => {
// 在发送请求前做些什么
return config
},
error => {
// 请求错误的时候做什么 **********
401 请求超时 404 not found
return Promise.reject(error)
}
);
- 取消正在进行的http请求
let source = axios.CancelToken.source(); // 生成一个source对象,里面有一个CancelToken
axios.get('user/login', {
cancelToken: source.token
}).then(res => {
console.log(res);
}).catch(err => {
console.log(err);
});
// 取消请求(message 可选)
source.cancel('cancel http');
四、封装axios
- 封装api
const CONTACT_API = {
// 获取联系人列表
getContactList: {
method: 'get',
url: '/contactList'
}
};
export default CONTACT_API;
附上自己的封装
// api.js
const api = {
login: {
url: '/users/login',
method: 'put'
},
getGroup: {
url: '/group/all',
method: 'get'
}
};
export default api;
// request.js
import axios from 'axios';
import service from './api';
import {Toast} from 'vant';
import store from '../src/store/index';
import router from '../src/router/index';
// 根据环境配置
if (process.env.NODE_ENV === 'development') {
axios.defaults.baseURL = 'http://127.0.0.1:3000';
} else if (process.env.NODE_ENV === 'production') {
axios.defaults.baseURL = 'http://api.123dailu.com/';
}
// 请求超时时间
axios.defaults.timeout = 5000;
// 请求头设置
axios.defaults.headers.get['ANSWER_ACCESS_TOKEN'] = 'store.getters.token';
let instance = axios.create();
const Http = {}; // 包裹请求方法的容器
// 请求格式/参数的统一
for (let key in service) {
let api = service[key];
Http[key] = async function (
params, // 请求参数 get: url put,post,patch: data delete: url
isFormData = false, // 标识是否时form-data请求
config = {} // 配置参数
) {
let url = api.url;
let newParams = {}; // 用于form-data与json的转换
// Content-type是否是form-data对象
if (params && isFormData) {
// 转换为把form-data
newParams = new window.FormData();
for (let i in params) {
newParams.append(i, params[i])
}
} else {
newParams = params
}
// 不同请求的判断
let response = {}; // 盛放请求的返回值
if (api.method === 'post' || api.method === 'put' || api.method === 'patch') {
try {
response = instance[api.method](url, newParams, config)
} catch (err) {
response = err;
}
} else if (api.method === 'delete' || api.method === 'get') {
config.params = newParams;
// 若参数需要放到data里,config.data
try {
response = await instance[api.method](url, config)
} catch (err) {
response = err;
}
}
return response; // 返回请求的响应值
};
}
// 请求拦截器
instance.interceptors.request.use(
config => {
// 每次发送请求之前判断是否存在token,如果存在,则统一在http请求的header都加上token,不用每次请求都手动添加了
// 即使本地存在token,也有可能token是过期的,所以在响应拦截器中要对返回状态进行判断
const token = store.getters.token;
token && (config.headers.ANSWER_ACCESS_TOKEN = token);
Toast.loading({
mask: false, // 是否有阴影
duration: 0, // 0为一直存在
forbidClick: true, // 是否禁止点击
message: '加载中...'
});
return config;
},
error => {
Toast.clear();
Toast('请求错误,请稍后重试');
}
);
// 响应拦截器
instance.interceptors.response.use(
res => {
if (res.status === 200) {
Toast.clear();
return res.data;
}
},
// 服务器状态码不是200的情况
error => {
console.log(error);
Toast.clear();
if (error.response.status) {
switch (error.response.status) {
// 401: 未登录
// 未登录则跳转登录页面,并携带当前页面的路径
// 在登录成功后返回当前页面,这一步需要在登录页操作。
case 401:
router.replace({
path: '/login',
query: {redirect: router.currentRoute.fullPath}
});
Toast('401: 未登录');
break;
// 403 token过期
// 登录过期对用户进行提示
// 清除本地token和清空vuex中token对象
// 跳转登录页面
case 403:
Toast({
message: '登录过期,请重新登录',
duration: 1000,
forbidClick: true
});
// 清除token
localStorage.removeItem('token');
store.commit('changeToken', null);
// 跳转登录页面,并将要浏览的页面fullPath传过去,登录成功后跳转需要访问的页面
setTimeout(() => {
router.replace({
path: '/login',
query: {
redirect: router.currentRoute.fullPath
}
});
}, 1000);
break;
// 404请求不存在
case 404:
Toast({
message: '网络请求不存在',
duration: 1500,
forbidClick: true
});
break;
// 其他错误,直接抛出错误提示
default:
Toast({
message: '404 请求错误,请稍后重试',
duration: 1500, // 0为一直存在
forbidClick: true // 是否禁止点击
});
}
return Promise.reject(error.response);
}
}
);
export default Http;
分装 axios 更新
import axios from 'axios';
import server from './api';
// server 循环遍历输出不同的请求方法
let instance = axios.create({
baseURL: 'http://localhost:8080',
timeout: 3000
});
// 包裹循环遍历出的请求方法
const Http = {};
for (let key in server) {
let api = server[key]; // url method
Http[key] = async function (
params,
isFormData = false,
config = {}
) {
let url = api.url;
let newParams = {};
if (params && isFormData) {
newParams = new FormData();
for (let i in params) {
newParams.append(i, params[i])
}
} else {
newParams = params;
}
let response;
if (api.method === 'get' || api.method === 'put' || api.method === 'patch') {
try {
response = await instance[api.method](api.url, newParams, config);
} catch (e) {
console.log(e);
}
} else {
try {
response = await instance[api.method](api.url,config);
} catch (e) {
console.log(e);
}
}
return response
}
}
instance.interceptors.request.use(
config => {
if (store.state.token) {
config.headers.token = `${store.state.token}`
}
return config
}, err => {
console.log(err);
}
);
instance.interceptors.response.use(
res => {
return res
}, err => {
if (err.response) {
switch (err.response.status) {
case 401:
/*
* 返回401 表示前端的token 已经失效
* 状态码 前后端统一
* 清楚vuex 种的token
*/
}
}
return Promise.reject(err)
}
);
export default Http;
欢迎大家留言评论