关于异步请求

276 阅读3分钟

「这是我参与2022首次更文挑战的第5天,活动详情查看:2022首次更文挑战

关于异步请求(XHR)

同步请求:当浏览器向服务器发送请求,发送成功之后,浏览器处于等待状态,等到服务器返回响应数据,浏览器接收数据并做相应处理后重新加载页面

基于以上,当浏览器发送请求后就只能等待,无法执行别的事件,所以引入异步请求

异步请求:大部分浏览器内置了XMLHttpRequest对象,浏览器把请求交给了XMLHttpRequest,浏览器发送请求后,不需要等待响应,待服务端响应后,刷新页面局部内容

关于Ajax

Ajax 全名是Asynchronous Javascript and XML(异步的JavascriptXML技术)

Axios

Axios 是一个基于Promise 用于浏览器和Node.jshttp客户端

Axios 基于浏览器内置对象XMLPromise对象,通过node.js发起http请求;通过拦截器配置请求数据和转换响应数据并做相应处理,基于XML,因此也支持取消请求

Axios请求的封装

// 需要引入axios

// 创建axios实例
const service = axios.create({
  baseURL: process.env.BASE_API,
  timeout: 15000
});

// 配置请求拦截器
service.interceptors.request.use(
  config => {
    // 统一网络请求的请求头
    if (store.getters.token) {
      config.headers['Authorization'] = "XXX";
    }
    return config;
  },
  error => {
    // ...... 对错误信息进行统一处理
    Promise.reject(error);
  }
);

// 配置响应拦截器
service.interceptors.response.use(
  response => {
      // ...... 对响应数据进行统一处理
      return response;
  },
  error => {
    // ...... 对错误信息进行统一处理
    return Promise.reject(error);
  }
)
export default service

fetch

关于fetch的浏览器支持度,如下图,需要提醒的是,fetch不提供对IE的支持。 fetch-caniuse.png fetch提供一个JS接口,用于定义RequestResponse对象。它基于Promise,但是对于服务端响应的404、500等状态码,fetch都把它标记为resolve,仅当网络故障或请求中断,才会标记为reject

对于Response对象,需要做下.json()处理,来把HTTP响应解析为JSON数据

关于fetch无法跟Ajax一样中断请求的问题,浏览器现已开始对Abort API添加实验性支持。

fetch 现也还不支持超时控制,且跨域默认不会带cookie

跨域

说到异步请求的封装,那前端的跨域配置也是必须的了。

对于普通的跨域请求,服务端设置Access-Control-Allow-Origin即可。

对于需要带cookie的请求,前后端都需要设置,设置方法有:

  1. 对于vue框架的跨域,可通过webpack配置文件,配置devServer,若需要支持websocket跨域,配置ws:true即可
devServer: {
    proxy: {
        '/api':{
          target: APP_BASE_URL,
          ws: true,
          secure: false,// 如果是https接口,需要配置这个参数
          changeOrigin: true
        }
    }
}
  1. 对于nuxt框架的跨域,配置也是类似的 nuxt.config.js文件中配置如下:
 // 配置代理
  axios: {
    proxy: true
  },
  proxy: {
    '/service': {
      target: APP_BASE_URL
    }
  }
  1. 对于非vue框架的跨域,可通过ng进行配置
server {
	listen       8080;
	server_name  127.0.0.1;

	location / {
		proxy_pass  http://59.110.XXX.XXX;
		client_max_body_size    10m; #表示最大上传10M,需要多大设置多大。
   
		proxy_read_timeout          300s;
		proxy_redirect              off;
		proxy_set_header            Host $host;
		proxy_set_header            X-real-ip $remote_addr;
		proxy_set_header            X-Forwarded-For $proxy_add_x_forwarded_for;
	}    
}
  1. 还有个方法,直接将chrome浏览器设置成跨域浏览器,设置方法可以自行百度搜索~

asyncawait语法糖的使用

  1. asyncawaitgenerator函数的语法糖,写法上替代了Promise回调函数。await意图等待Promise对象的状态被resolved,对于Promise状态被reject的情况,需要通过try catch来获取。写法如下:
      async handleDelete(data) {
        try {
          await deleteBatch({ list: data });
          this.$message.success('删除成功!');
        } catch (e) {
          // 处理请求失败的情况
          this.$message.error('删除失败!');
        }
      },
  1. asyncawait使用过程中需要注意的是,await必须在async函数的上下文中的。
  2. 注意以下:多个异步 不同写法的执行情况:
 async test() {
    let p1 = getSwYw();
    let p2 = getOrderNum({orderType: 0});
    let p3 = checkActive();
    try {
      let res = await Promise.all([p1, p2, p3]);
      console.log('成功', res)
    } catch(e) {
      console.log('失败', e)
    }
}

这种写法:三个异步请求是并发执行的,如下图: 并发请求.png 三个请求完成后才有结果输出,如下图: Promise.all 返回结果.png

  async test() {
    await getSwYw();
    await getOrderNum({orderType: 0});
    await checkActive();
    console.log('成功');
  },

这种写法: 三个异步请求是继发执行的,如下图: 继发执行.png 跟上面的一样,3个请求完成后才会输出“成功” 继发请求结果输出.png