前后端交互
ajax
ajax封装
function req({
method='get',
url,
data,
headers,
responseType
}) {
return new Prmise((resolve, reject) => {
let xhr = new XMLHttpRequest();
console.log(xhr.readyState) // 0 (未初始化)还没有调用send()方法 (没有开始)
xhr.open(method, url);
console.log(xhr.readyState) // 1 (载入)已调用send()方法,正在发送请求 (正在发送中)
for(let key in headers) {
xhr.setRequestHeader(key, headers[key]);
}
if(responseType){
xhr.responseType = responseType;
}
if(typeof data === 'object') {
data === JSON.stringify(data);
xhr.setRequersHeader('Content-Type', 'application/json;charset=UTF-8')
}
if(data) {
xhr.send(data);
}else {
xhr.send();
}
console.log(xhr.readyState) // 1 (载入)已调用send()方法,正在发送请求 (正在发送中)
// onreadystatechange 状态改变都会触发
xhr.onreadystatechange = function() {
console.log(xhr.readyState) // 依次输入 2、3、4
// 2、(载入完成)send()方法执行完成 (已发送)
// 3、(交互)正在解析相应内容 (正在响应中)
// 4、(完成)响应内容解析完成,可以在客户端调用 (结束响应)
if(xhr.readyState === 4) {
if(xhr.status === 200) {
resolve(xhr.response);
}else {
reject(xhr.response);
}
}
}
})
}
async function run() {
let res = await req({
url: '/index.html',
})
console.log(res)
}
run()
长链接
一直返回xhr.readyState === 3 状态
长链接与ws区别:
长链接:在http协议下类似摆脱【先请求后响应】模型的一种方式,实现【服务器长时间主动向客户端通信】的效果 一次请求多次响应
ws: 全双工通信 不受服务器 客户端数显,谁多发的限制 任意请求响应
聊天室实现方式:
1、轮询ajax;
2、服务器长链接;
3、websocket;
4、Socket.io (根据兼容性封装以上三种交互方式)
上传
同步上传
浏览器默认发生的行为 上传成功后存在跳转
<form action="/upload" method="post" enctypr="multipart/form-data">
<input type="file" name="file"/>
<button>上传</button>
</form>
异步上传
<input id="file" type="file" name="file"/>
<button id="ajaxAsyncUpload">上传</button>
ajaxAsyncUpload.onclick = funciton(){
let f1 = file.files[0];
// 创建容器(H5之后)
let fd = new FormData();
fd.append('file', f1);
req({
url: '/upload',
method: 'post',
data: fd,
})
}
下载
同步下载
<a href="/11.txt" download="download.txt">同步下载</a>
异步下载
<button id="ajaxAsyncDownload">下载</button>
function downloadForTag(blob, filename) {
// 内存地址指向文件
let url = window.URL.createObjectURL(blob);
// 创建a标签赋值url
let a = document.createElement('a');
a.href = url;
// 不指定download 就跳转了
a.download = filename;
a.style.display = 'none';
// 插入元素
document.body.appendChild(a);
// 点击a标签
a.cliclk();
// 释放资源
a.remove();
window.URL.revokeObjectURL();
}
ajaxAsyncDownload.onclick = async funciton(){
let blobRes = await req({
url: '/11.txt',
// blob 前端封装的一个文件容器
// responseType可用: text arraybuffer blob
responseType: 'blob'
});
downloadForTag(blobRes, 'download.txt')
}
文件合并
<button id="fileJoin">合并</button>
fileJoin.onclick = async funciton(){
let res = await req({
url: '/chunkfile',
responseType: 'blob'
});
// arrayBuffer: blob文件对象底层的容器
let arrayBuffer = await res.arrayBuffer();
// 拼接双倍
downloadForTag(new Blob([arrayBuffer, arrayBuffer]), '合并.txt')
}
文件切割
<button id="fileSplit">切割</button>
fileSplit.onclick = async funciton(){
let res = await req({
url: '/chunkfile',
responseType: 'blob'
});
let arrayBuffer = await res.arrayBuffer();
let len = arrayBuffer.bytelength/2;
fo(let i = 0; i < arrayBuffer.bytelength; i+= len) {
downloadForTag(new Blob([arrayBuffer.slice(i, i+len)]), `切割${i}.txt`)
}
}
跨域
同源策略: 针对于ajax 发起网站 与 接口访问网站 的一种限制
协议、接口、域名不一致都会引起跨域
解决方式:
1、jsonp(利用外链请求【img(jpg) script(js) link(css) iframe(html)】非ajax不受限制的特点来实现);
2、CORS(后端让浏览器不要多管闲事);
3、代理(当前页面服务器帮助外面转发,不存在跨域之说)
JSONP
一种处理跨域的方式 和json没有多大关系
数据传输是json数据
利用外链非ajax不受同源策略影响实现站外js执行,并传递数据
只能是get请求 前端和后端都需要coding
优点:利用浏览器外链,兼容性好
缺点:只能get请求;代码前端后端都需要编写
<script>
function myJsonP(url, fn) {
// 1、动态创建script标签
let script = document.createElement('script');
// 1.5 定义动态的方法名
let fnName = 'callbackName_' + Date.now();
// 2、设置src
script.src = url + '?callback=' + fnName;
// 2.5 声明方法名
window[fnName] = function(data) {
// 4、使用完毕 释放资源
script.remove();
delete window[fnName];
fn(data);
}
// 3、插入到文档中
document.body.appendChild(script);
}
function myJsonP_promise(url) {
return new Peomise((res,rej) => {
// 1、动态创建script标签
let script = document.createElement('script');
// 1.5 定义动态的方法名
let fnName = 'callbackName_' + Date.now();
// 2、设置src
script.src = url + '?callback=' + fnName;
// 2.5 声明方法名
window[fnName] = function(data) {
// 4、使用完毕 释放资源
script.remove();
delete window[fnName];
res(data);
}
// 3、插入到文档中
document.body.appendChild(script);
})
}
</script>
<script>
myJsonP('http://localhost:4567/jsonp' ,(data) => {
console.log(data)
})
async function run() {
let res = awiat myJsonP_promise('http://localhost:4567/jsonp')
console.log(res)
}
</script>
CORS
跨站资源共享
1、让后端允许访问的域名: Access-Control-Allow-Origin: * (最好为动态对方ip地址)
CORS场景下如果使用cookie不能写*
2、Access-Control-Allow-Methods
3、Access-Control-Allow-Headers 若有自定义请求头需要在这声明
4、允许携带cookie: Access-Control-Allow-Credentials: true
客服端也需要设置允许跨域携带cookie: withCredentials: true
优点:支持各种请求方式
缺点:兼容性差点,不够安全(全网暴露资源)
代理
正向代理(为客户端服务):隐藏了客户端;反向代理(为服务端服务):隐藏了服务器ip,客户端不知道服务器ip
优点:无兼容性;支持各种请求方式,相对安全
RestFul
高效前后端开发的约定;提供一个模块名;剩下的用get/post/delete/put/patch请求方式分别完成不太的行为
get:获取
post:新增
delete:删除
put:全量更新
patch:增量更新