http协议

2023/11/29 软件工程

# 协议是什么?

http协议是一种协议,什么是协议呢?为什么要使用协议呢?

协议是实体对外交互的一种约定,协议本身将这些实体解耦,解耦是可以通过第三方实体解耦,但是那样的话第三方实体就需要实现所有对应的实现,这么说好像这个思路是可以的,但这几乎不可能,因为这意味着所有所有的实体都要通过这个第三方实体,安全性,管理第三方实体的成本,通信集中到第三方实体将有性能问题等等,都意味这这条路不可行。

从另一个角度来看,协议是一种抽象,是一种标准,是独立实体之间的约定,由独立实体实现并自己负责与其他实体无关。

# Ajax请求

http协议是一种规范,具体是由客户端和服务端实现的,客户端是架构上的叫法,接近http协议的叫法是用户代理。用户代理有多种实现,其中浏览器是一种。浏览器也可以定义多种http请求,比如导航请求、ajax请求,虽然在这些方式有所不同或有所抽象限制,但请求本质上的内容还是在http协议的范围。

  • ajax请求在chrome浏览器是由XMLHttpRequest对象或fetch方法实现的,而浏览器导航请求属于普通请求。

  • ajax请求是异步的,也就是说它不会阻塞浏览器的其他操作,而浏览器导航请求是同步的,也就是说它会等待服务器的响应才继续执行。

  • ajax请求不会刷新或跳转页面,而浏览器导航请求会刷新或跳转页面。

  • ajax请求可以自定义请求头和响应格式,而浏览器导航请求只能使用默认的请求头和响应格式。

来看看普通请求的概念,都要忘了这回事了。浏览器的普通请求是指通过点击链接、输入地址、提交表单等方式发出的http请求,它会导致页面的刷新或跳转。浏览器的普通请求一般是同步的,也就是说它会等待服务器的响应才继续执行。

# XMLHttpRequest

在实践中通常使用这个接口来进行http请求,这里重点来看看请求数据和响应数据在接口上是怎么体现的?

前端代码:

<template>
  <div id="app">
    <button @click="handleClick">http请求</button>
  </div>
</template>

<script>
  export default {
    name: 'App',
    data() {
      return {
        style: {},
        imgSrc: ''
      }
    },
    mounted() {
    },
    methods: {
      handleClick() {
        // 创建XMLHttpRequest对象
        let xhr = new XMLHttpRequest();
        // 建立对服务器的调用,指定请求方法、请求地址和是否异步
        xhr.open("GET", "example.com/api/data", true);
        // 向服务器发送请求,如果是POST请求,需要传入请求体
        xhr.send();
        // 监听服务器的响应状态和数据
        xhr.onreadystatechange = function () {
          // readyState为4表示请求已完成,status为200表示响应成功
          if (this.readyState == 4 && this.status == 200) {
            // responseText为响应数据,根据内容类型进行解析
            console.log(xhr.responseText);
          }
        };
      }
    }
  }
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

后端代码:

import type { VercelRequest, VercelResponse } from '@vercel/node';
import {allowCors} from "../src/utils";

async function heart(
  request: VercelRequest,
  response: VercelResponse,
) {
  response.status(200).json({
    body: request.body,
    query: request.query,
    cookies: request.cookies,
  });
}

export default allowCors(heart)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

浏览器的响应数据:

{"body":"","query":{},"cookies":{}}
1

xhr.responseText的数据:

{"body":"","query":{},"cookies":{}}
1

可以看到http状态码由后端定义,通常是框架定义。浏览器的响应面板的数据通常是后台服务器的部分返回数据。

响应数据分为三层:

  • 基础层:http协议定义的状态码和状态文本。比如5xx代表服务器出现错误,4xx用户代理端错误,定义了常见的一些状态码及状态文本。如果状态码为500,具体的错误还需要服务层定义更详细的信息。
  • 服务层:区分服务器是否执行成功(不是用户期望的成功,是服务器是否正常执行业务。比如用户登录失败只是密码失败,但服务器执行是成功的)
  • 前端业务层:处理业务数据。通常业务数据只有一个流程,如果需要一些用户容错流程,则可以定义业务状态码。

第一层通常使用的是服务端框架根据http协议已定义的,响应数据的后面两层层在json上的体现是:

{
  "success": true,
  "data": {
    "code": 0,
    "data": null,
    "message": ""
  },
  "message": 
}
1
2
3
4
5
6
7
8
9

有的省略了第三层,即少了一层业务层,没有规范这一层会导致比较混乱。

# Axios

axios中的response.data为上面包括两层的json,应该把业务层response.data.data给后面业务代码执行,所以axios配置的示例代码如下:

import axios from 'axios'

const instance = axios.create({
  baseURL: ''
})

instance.interceptors.request.use(config => {
  // 在发送请求之前做些什么
  return config;
}, error => {
  // 对请求错误做些什么
  return Promise.reject(error);
});

instance.interceptors.response.use(response => {
  // 对响应数据做点什么
  return response.data.data;
}, error => {
  // 对响应错误做点什么
  return Promise.reject(error);
});

export default instance
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

后面再看看axios的错误响应处理。

服务层的报错在axios拦截器可以做处理,通常不用在业务代码再来处理服务层的错误。

而业务层的catch是来处理业务代码的意外错误,业务层的响应错误状态是在then处理的。(通常code在代码可以省略,因为没有其他错误流程的业务)。

# 服务层的statusText英文问题

axios是一个基于Promise的HTTP库,可以用在浏览器和Node.js中。它的响应结构中包含了statusText属性,来自服务器响应的HTTP状态信息。一般来说,statusText是英文的,例如’OK’或’Not Found’,但是如果服务器返回了中文的状态信息,那么axios也会显示中文的statusText。

可以在axios配置那里进行处理。

更新时间: 2023/11/29 15:42:16