AJAX

应用场景

实现

原生方式

let xhr = new XMLHttpRequest();// 发送get请求 通过url传递参数xhr.open('get',"/home");xhr.send();xhr.onload = function(){    console.log(xhr.responseText);}
xhr.open('post',"/home");xhr.setRequestHeader('Content-Type',"application/json");xhr.send('{"name":"jntm"}');

ajax状态码

xhr.onreadystatechange = function(){    console.log(xhr.readyState);}
区别描述onload事件onreadystatechange事件
是否兼容IE低版本不兼容兼容
是否需要判断Ajax状态码不需要需要
被调用次数一次多次

错误处理

xhr.status

会触发xhr对象下面的onerror事件,在onerror事件处理函数中对错误进行处理

ajax封装

function ajax(req) {    let xhr = new XMLHttpRequest();    let params = "";    for (let attr in req.data) {        params += attr + "=" + req.data[attr] + "&";    }    params = params.substr(0, params.length - 1);    xhr.open(req.type, req.type != 'get' ? req.url:req.url + "?" + params);    for(let attr in req.headers){        xhr.setRequestHeader(attr,req.headers[attr]);    }    if (req.type == 'get'){        xhr.send();    }else{        if (req.headers['Content-Type']=='application/json'){            xhr.send(JSON.stringify(req.data));        }else{            xhr.send(params);        }    }    xhr.onload = function () {        let contentType = xhr.getResponseHeader("Content-Type");        let responseText = xhr.responseText;        if (contentType.includes("application/json")){            responseText = JSON.parse(responseText);        }        if (xhr.status === 200) {            req.success && req.success(responseText);        } else {            req.error && req.error(responseText);        }    };}ajax({    url: '/home',    type: 'get',    data: {name: "cxk", age: 18},    headers:{        "Content-Type":"application/json"    },    success: function (res) {        console.log('normal res', res);    },    error: function (res) {        console.error('error res', res);    }})

JQuery实现方式

$.ajax({    url:"./" , // 请求路径    type:"POST" , //请求方式    //data: "username=jack&age=23",//请求参数    data:{"username":"jack","age":23},    success:function (data) {        alert(data);    },//响应成功后的回调函数    error:function () {        alert("出错啦...")    },//表示如果请求响应出现错误,会执行的回调函数});

发送jsonp请求

$.ajax({    url: 'http://www.example.com',    // 指定当前发送jsonp请求    dataType: 'jsonp',    // 修改callback参数名称    jsonp: 'cb',    // 指定函数名称    jsonCallback: 'fnName',    success: function (response) {} })
$("#form").serialize(); // 将表单输入的内容转换成如k=v&a=b这种形式

全局事件

.ajaxStart()     // 当请求开始发送时触发.ajaxComplete()  // 当请求完成时触发

配合nprogress来实现页面加载进度条

FormData

简单使用

<form id="form">    <input type="text" name="username"/>    <input type="password" name="password"/>    <input type="file" name="file">    <input type="button" id="btn"/></form>
let form = document.querySelector("#form");let formData = new FormData(form);let xhr = new XMLHttpRequest();xhr.open('post','/formData');xhr.send(formData);

实例方法

// 获取表单对象属性formData.get('username');// 设置表单对象属性formData.set("username","cxk");// 删除表单对象属性formData.delete("username");// 追加表单对象属性,属性名已存在的情况下,set会覆盖,append会保留formData.append("username","cxk");

文件上传进度展示

xhr.upload.onprogress = function (ev) {    console.log(ev.loaded / ev.total)}

图片上传实时预览

var file = document.querySelector('#file');file.onchange = function(){    var reader = new FileReader();    reader.readAsDataURL(this.files[0]);    reader.onload = function(){        document.querySelector('.img-thumbnail').src = reader.result;    }}

使用Promise发送ajax

function query() {    return new Promise((resolve, reject) => {        let xhr = new XMLHttpRequest();        xhr.onreadystatechange = () => {            if (xhr.readyState != 4) {                return;            }            if (xhr.readyState == 4 && xhr.status == 200) {                resolve(xhr.responseText);            } else {                reject(xhr.status);            }        };        xhr.open('get', '/home');        xhr.send();    });}query().then(r => console.log(r)).catch(r => console.error(r))

fetch

Fetch API是新的ajax解决方案

fetch不是ajax的进一步封装,而是原生js,没有使用XMLHttpRequest对象

fetch('/home').then(data=>{    return data.text();}).then(data=>{    console.log(data);});

data是一个response对象,其中包括返回的一堆原始字节,这些字节需要在收到后,需要我们通过调用方法将其转换为相应格式的数据,比如JSONBLOB或者TEXT等等

let formData = new FormData();formData.append('username','cxk');formData.append('password','jntm');fetch('/formData',{    method:'post',    body:formData})

axios

axios.get('/home')    .then(res=>{        console.log(res);    })
let formData = new FormData();formData.append('username','cxk');formData.append('password','jntm');// 默认传递的是jsonaxios.post('/formData',formData) .then(res=>{     console.log(res); })
async function f(){    let res =  await axios.post('/formData',formData);    console.log(res);}

全局参数

// 配置公共的请求头 axios.defaults.baseURL = 'https://api.example.com';// 配置 超时时间axios.defaults.timeout = 2500;// 配置公共的请求头axios.defaults.headers.common['Authorization'] = AUTH_TOKEN;// 配置公共的 post 的 Content-Typeaxios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';

拦截器

// 请求拦截器axios.interceptors.request.use(function(config) {    console.log(config.url)    // 这里一定要return   否则配置不成功    return config;}, function(err){    // 对请求错误做点什么    console.log(err)})// 响应拦截器axios.interceptors.response.use(function(res) {    console.log(res.data);    return res.data;}, function(err){    console.log(err)});

同源策略

ajax受同源策略限制

JSONP

原理:

客户端定义一个函数:

function fn (data) { // 接收到服务器data后的一些处理 }

服务端返回一个函数调用:

const data = 'fn({name: "张三", age: "20"})';

客户端使用script可以跨域加载数据

<script src="server_ajax_address"></script>

这样客户端就可以获取服务端的数据

function fn(data){    console.log('server res',data);}let script = document.createElement('script');script.src = '/jsonp?v=1';document.body.appendChild(script);
@GetMapping("/jsonp")public String jsonp(){    return "fn({name:'cxk',age:18})";}

优化

CORS

全称为 Cross-origin resource sharing,即跨域资源共享,它允许浏览器向跨域服务器发送 Ajax 请求,克服了 Ajax 只能同源使用的限制

通过设置Access-Control-Allow-OriginAccess-Control-Allow-Methods响应头来允许哪些源可以使用哪些方法访问

@RestController@CrossOrigin("*")public class Controller {...}

withCredentials:指定在涉及到跨域请求时,是否携带cookie信息,默认值为false

使用后端服务器辅助访问