
前言
本篇博客主要回顾了日常请求的封装以及拓展,便于后续开发新项目时快速使用
面试回答
1.get和post的区别:从传参上来讲,get请求会将参数拼接到url上,而post则是放在请求体中。从数据量来讲,get请求有url长度限制,所以post请求允许发送的数据比get更大。从安全性上来讲,post请求不会被缓存、保存在记录上,因此更加安全。从数据类型上来讲,post请求能发送更多的数据类型。
2.options请求:option请求一般出现在复杂请求中,比如put、delete请求或者带json格式、自定义头部这样的。复杂请求可能会对数据产生副作用,所以在请求前会先发起option请求,确认当前页面是否在许可名单中,然后再发起正常的请求。
3.本地存储:常用的本地缓存有cookie、localStorage、sessionStorage、indexedDB,cookie一般用于状态存储,它的容量较小,请求经常会带上这个cookie,造成性能浪费,且容易被获取篡改;sessionStorage属于会话级存储,容量相对较大,不参与请求,能够持久化存储,用于临时保存同一窗口的数据,在关闭窗口或页签之后将会删除这些数据。localStorage与sessionStorage基本一致,只不过localStorage关闭浏览器也不会被清理,所以需要手动清理,避免浪费;indexedDB也是持久化存储,不过用到的会比较少。
4.轮询:ajax轮询一般分为两种。一种是设定一个定时器,时间一到就发请求,这种比较消耗资源。还有一种是ajax长轮询,它需要服务器接到请求后保持连接,直到有新消息才关闭连接。实现上就是在第一次请求的时候,在成功以及失败的回调中再起发起请求,不过这种方式数据顺序无法保证,难以管理。Websocket是html5中的一个持久化协议,它最大的特点就是可以双向通信,允许服务器主动的向客户端推送信息,这种方式实时性比较强,创建连接后,可以通过websocket的数据包头部进行数据交换。使用时,一般我们会new一个websocket对象,然后用websocket对应的事件去执行,比如open建立连接、send发送数据、message接收数据、error通信异常、close关闭连接。
知识点
从本质上来讲,封装http请求,相当于写一个公共方法,然后供其他组件使用,只不过书写方式以及拓展可以拿来讲一讲。
1.GET和POST的区别
- 使用Get请求安全性低,可以收藏为书签,可以被缓存,参数在URL中显示,且不同浏览器存在不同的长度限制;而Post请求反之,不可以被收藏,除非在响应头中设置Cache-Control/Expires字段,否则也不可以被缓存,参数储存在请求体重,无长度限制。
- GET请求一般不具有请求体,因此只能进行url编码,只允许ASCII字符,而POST请求支持多种编码方式,也支持二进制数据
- 使用Get请求发送数据量小,Post请求发送数据量大
- GET请求具有幂等性(多次请求不会对资源造成影响),POST请求不幂等;
- GET请求一般不具有请求体,请求中一般不包含100-continue 协议,所以只会发一次请求,而POST请求在发送数据到服务端之前允许双方"握手",客户端先发送Expect:100-continue消息,询问服务端是否愿意接收数据,接收到服务端正确的100-continue应答后才会将请求体发送给服务端,服务端再响应200返回数据。
2.复杂请求
符合以下条件的请求,即为简单请求:
- 请求方式为GET、HEAD、POST时的请求;
- 认为设置规范集合之内的首部字段, 如Accept/Accept-Language/Content-Language/Content-Type/DPR/Downlink/Save-Data/Viewport-Width/Width
- Content-Type的值仅限于下列三者之一,即application/x-www-form-urlencoded、multipart/form-data、text/plain;
- 请求中的任意XMLHttpRequestUpload对象均没有注册任何事件监听器
- 请求中没有使用ReadableStream对象。
除此之外,均为复杂请求。
复杂请求就会触发options预检请求,预检请求会额外占用服务器资源,还会延迟真正请求的发起时间,导致页面上性能变差 。
3.本地存储
- cookie
cookie本质上是浏览器里面存储的一个很小的文本文件,内部以键值对的方式存储。向同一个域名下发送请求都会携带相同的Cookie,服务器拿到Cookie进行解析,就能拿到客户端的状态。
容量缺陷:Cookie的体积上限只有4KB,只能用来存储少量的信息。
性能缺陷:Cookie是紧跟域名的,不管域名下面的某个地址需不需要这个Cookie,它都会携带上完整的Cookie。这样随着请求数据的增多,很容易造成性能上的浪费。
安全缺陷:由于Cookie以纯文本的形式在浏览器和服务器中传递,很容易被非法用户截获,然后进行一系列的篡改,并在Cookie的有效期内重新发送给服务器。另外,在HTTPOnly为false的情况下,Cookie信息能直接通过JS脚本读取。
cookie属性
属性 | 说明 |
---|---|
key | cookie 的键(名称) |
value | cookie 的值 |
max_age | cookie 被保存的时间数,单位为秒。 |
expires | 具体的过期时间,一个datetime 对象或UNIX时间戳 |
path | 限制cookie 只在给定的路径可用,默认为整个域名下路径都可用 |
domain | 设置cookie 可用的域名,默认是当前域名,子域名需要利用通配符domain=.当前域名 |
secure | 如果设为True ,只有通过HTTPS 才可以用 |
httponly | 如果设为True ,禁止客户端JavaScript 获取cookie |
- session
session大小理论上没有限制,安全性也大于cookie,保存于服务器端。
缺陷:Session保存的东西越多,就越占用服务器内存,对于用户在线人数较多的网站,服务器的内存压力会比较大。依赖于cookie(session id保存在cookie),如果禁用cookie,则要使用URL重写,不安全创建session变量有很大的随意性,可随时调用,不需要开发者做精确地处理,所以,过度使用session变量将会导致代码不可读而且不好维护。
- storage
sessionStorage属于会话级存储,容量相对较大,不参与请求,能够持久化存储,用于临时保存同一窗口的数据,在关闭窗口或页签之后将会删除这些数据。localStorage与sessionStorage基本一致,只不过localStorage关闭浏览器也不会被清理,所以需要手动清理,避免浪费;indexedDB也是持久化存储,不过用到的会比较少。
- indexedDB
应用于storage数据量过大时,indexedDB没有存储限制,不过使用上不大方便。
4.ajax实现原理及使用
Ajax是一种异步请求数据的web开发技术, 其核心是浏览器提供的XMLHttpRequest对象,使得浏览器可以发出HTTP请求与接收HTTP响应,等收到XHR返回来的数据再渲染页面。
来看一下XMLHttpRequest基本使用:
scss
//1.创建XMLHttpRequest对象,如果是IE5,IE6则需要考虑兼容性
var ajax = new XMLHttpRequest();
//2.规定请求的类型、URL、以及是否异步处理请求
ajax.open('POST',url,true);
//3.发送信息至服务器时内容编码类型,即请求头设置
ajax.setRequestHeader('Content-type','application/x-www-form-urlencoded');
//4.发送请求,send里放着请求参数,即请求体
ajax.send("name=zxp&age=18");
//5.响应服务器数据
ajax.onreadystatechange = funciton(){
if(obj.readyState ==4 &&(obj.status == 200 || boj.status ==304)){
....
}
}
拓展:
1中IE5、6的兼容:var ajax=new ActiveXObject("Microsoft.XMLHTTP");
2中如果设置的是同步处理,可以通过ajax.responseText获得字符串形式的响应数据。
2中如果是GET请求,则需要在url上拼接上对应的参数,在4中直接填写null即可
5中的readyState有五个状态值:
0,未初始化,尚未调用.open()方法;
1,启动,已经调用.open()方法,但尚未调用.send()方法;
2,发送,已经调用.send()方法,但尚未接收到响应;
3,接收,已经接收到部分响应数据;
4,完成,已经接收到全部响应数据,而且已经可以在客户端使用了;
5.axios实例
测试url:123.207.32.32:8000/home/multidata
javascript
//request.js
import axios from 'axios'
import {Message} from 'element-ui'
import store from '@/store'
import {getToken} from '@/utils/auth' //获取登录后的token
//创建请求,设置超时时间以及请求的url
const service = axios.create({
baseURL:'xxxx',//完整的url会由axios进行拼接 = baseURL + 传入的request url
//withCredentials:true,//跨域请求时发送cookies
timeout:30000// 请求超时时间
})
//request请求拦截
//拦截客户端请求信息,比如登录成功后,页面中所有请求都需要携带token,用于服务端判断用户登录信息
service.interceptors.request.use(
config=>{
if(store.getters.token){
config.headers['token'] = getToken()
}
return config
},error =>{
return Promise.reject(error)
}
)
//response返回拦截,对返回的数据初步处理
service.interceptors.response.use(
response=>{
const res= response.data
if(res.code !== '0000' ){
return Promise.reject('error')
}else{
return res
}
},error=>{
Message({
message:'xxxx',
type:'error'
})
return Promise.erject(error)
}
)
export default service
6.轮询
ajax轮询一般分为两种。一种是设定一个定时器,时间一到就发请求,这种比较消耗资源,如:
javascript
let index = 1;
setInterval(() => {
//发送请求
}, 1000);
//由于请求所耗时间不固定,所以可以优化为Promise + setTimeout的方式
const sleep = () => {
return new Promise(resolve => {
setTimeout(()=>{
//发送请求
resolve()
}, 1000);
});
}
还有一种是ajax长轮询,它需要服务器接到请求后保持连接,直到有新消息才关闭连接。实现上就是在第一次请求的时候,在成功以及失败的回调中再起发起请求。
Websocket是html5中的一个持久化协议,它最大的特点就是可以双向通信,允许服务器主动的向客户端推送信息,这种方式实时性比较强,创建连接后,可以通过websocket的数据包头部进行数据交换。
ini
const socket = new WebSocket("ws://localhost:8080");
socket.onopen = function () {
console.log("连接建立");
socket.send('hello');
};
socket.onmessage = function (e) {
console.log(e)
}
socket.onerror = function () {
console.log("连接发生错误");
};
socket.onclose = function () {
console.log("连接关闭");
};
使用时,一般我们会new一个websocket对象,然后用websocket对应的事件去执行,比如open建立连接、send发送数据、message接收数据、error通信异常、close关闭连接。
7.下载
- form表单提交
javascript
function downloadFile(downloadUrl,fileName){
//创建表单
const formObj = document.createElement('form')
formObj.action = downloadUrl
formObj.method = 'get'
formObj.style.display = 'none'
//创建input,主要用来传参
const formItem = document.createElement('input')
formItem.value = fileName//传参的值
formItem.name = 'fileName'//传参的字段名
//插入到网页中
formObj.appendChild(formItem)
document.body.appendChild(formObj)
formObj.submit()//发送请求
document.body.removeChild(formObj) //发送完清除掉
}
- window.open(url)/location.href = url
接口请求后,返回对应文件,然后直接通过浏览器window.open打开下载对应的文件。但是这种方式只能是get请求,且这种方式无法带上请求的header,如果需要带token等权限控制,则不满足需求。
ini
window.open(url)
location.href = url
- a标签的download
bash
<a href='test.jpg' download='test' > 下载</a>
//href为完整的url,download为下载文件的文件名
- 二进制流
new Blob(array,options):Blob构造函数接受两个参数,一个只读的二进制文件 array是数组,成员是字符串或二进制对象,是一个由ArrayBuffer,ArrayBufferView,Blob,DOMString等对象构成的Array,所以responseType可以设置为blob或ArrayBuffer,因为返回后都需要const blob = new Blob([res.data]),处理数据; options参数是可选的,是一个配置对象,目前只有一个属性type,值类型是字符串,表示数据的MIME类型,默认为空字符串。
二进制流下载方式:需要将请求的responseType设置为blob或者ArrayBuffer(否则可能出现乱码),然后转化成blob,比如xlsx文件,可以转换数据流const blob = new Blob([res.data],{type:'application/vnd.ms-excel'}),这里的type可以根据具体的文件格式调整,具体自行百度。
javascript
//处理请求头
const exportApi = async function(params){
try{
let data = await axios({
method:params.method,
url:params.url,
params:{ ...params.params },//get-->params ; post-->data
responseType:"blob"
})
return data
}catch(err){
throw error
}
}
//downloadingcb 下载中的回调
//downloadedcb 下载成功的回调
export default function download(event,_params={method:'post'},downloadingcb,downloadedcb){
downloadingcb.call() //下载中的回调,调用此方法的第一个then
const HttpRequest = exportApi(_params)
HttpRequest.then(res=>{
//请求异常处理
if(res.code === '500'){
return
}
//请求正常处理
const link = document.createElement('a')//创建a标签
const blob = new Blob([res.data],{type:'application/vnd.ms-excel'})//转化数据流
link.style.display = 'none' // 设置a标签不可见
link.href = URL.createObjectURL(blob)//设置a标签url
document.body.appendChild(link) //把a标签插入body页面
link.click() //点击a标签
document.body.removeChild(link) //移除a标签
downloadedcb.call()
}).catch(err=>{
downloadedcb.call()
})
}
最后
走过路过,不要错过,点赞、收藏、评论三连~