简介
Web
前后端中数据交互是实际项目业务中最为常见的一种需求。目前比较成熟的解决方案是采用axios
的方式,而其本质也就是计算机网络中的HTTP
的概念。
HTTP简介
HTTP
(hypertext transport protocol
)协议,即超文本传输协议,详细规定了浏览器和万维网服务器之间互相通信的规则和约定。
其用于数据交互的两个重要概念为:HTTP
请求报文和HTTP
响应报文。
HTTP请求报文
一个HTTP
请求报文由请求行request line
、请求头部header
、空行和请求数据4
个部分组成。
请求行
请求头部由关键字/值对组成,每行一对,关键字和值用英文冒号:
分隔。请求头部通知服务器有关于客户端请求的信息,典型的请求头有:
User-Agent
:产生请求的浏览器类型。
Accept
:客户端可识别的内容类型列表。
Host
:请求的主机名,允许多个域名同处一个IP
地址,即虚拟主机。
请求头部
请求头部由请求方法字段、URL
字段和HTTP
协议版本字段3
个字段组成,它们用空格分隔。例如,GET /index.html HTTP/1.1
。
HTTP
协议的请求方法有GET
、POST
、HEAD
、PUT
、DELETE
、OPTIONS
、TRACE
、CONNECT
。
其中最常见的为GET
(查询)和POST
(增加)请求。(PUT
请求对应于更新,DELETE
请求对应于删除)
GET请求
GET
方法要求服务器将URL
定位的资源放在响应报文的数据部分,回送给客户端。使用GET
方法时,请求参数和对应的值附加在URL
后面,利用一个问号(?
)代表URL
的结尾与请求参数的开始,传递参数长度受限制。
如果数据是英文字母/数字,原样发送,如果是空格,转换为+
,如果是中文/其他字符,则直接把字符串用BASE64
加密,得出如:%E4%BD%A0%E5%A5%BD
,其中%XX
中的XX
为该符号以16
进制表示的ASCII
。POST请求
POST
方法将请求参数封装在HTTP
请求数据中,以名称/值的形式出现,可以传输大量数据,这样POST
方式对传送的数据大小没有限制,而且也不会显示在URL
中。
空行
最后一个请求头之后是一个空行,发送回车符和换行符,通知服务器以下不再有请求头。
请求数据
请求数据不在GET
方法中使用,而是在POST
方法中使用。POST
方法适用于需要客户填写表单的场合。与请求数据相关的最常使用的请求头是Content-Type
和Content-Length
。
HTT响应报文
和请求报文类似,HTTP
响应报文也由三个部分组成,分别是:状态行、消息报头、响应正文。
在响应报文中唯一真正的区别在于第一行中用状态信息代替了请求信息。状态行status line
通过提供一个状态码来说明所请求的资源情况。
状态行格式
HTTP-Version Status-Code Reason-Phrase CRLF
其中,HTTP-Version
表示服务器HTTP
协议的版本;Status-Code
表示服务器发回的响应状态代码;Reason-Phrase
表示状态代码的文本描述。状态代码由三位数字组成,第一个数字定义了响应的类别,且有五种可能取值。
1xx
:指示信息—表示请求已接收,继续处理。2xx
:成功—表示请求已被成功接收、理解、接受。3xx
:重定向—要完成请求必须进行更进一步的操作。4xx
:客户端错误—请求有语法错误或请求无法实现。5xx
:服务器端错误—服务器未能实现合法的请求。
常见状态代码、状态描述的说明如下。
200 OK
:客户端请求成功。400 Bad Request
:客户端请求有语法错误,不能被服务器所理解。401 Unauthorized
:请求未经授权,这个状态代码必须和WWW-Authenticate报头域一起使用。403 Forbidden
:服务器收到请求,但是拒绝提供服务。404 Not Found
:请求资源不存在,举个例子:输入了错误的URL。500 Internal Server Error
:服务器发生不可预期的错误。503 Server Unavailable
:服务器当前不能处理客户端的请求,一段时间后可能恢复正常。
参考博客
Ajax简介
AJAX
全称为Asynchronous JavaScript And XML
,就是异步的JS
和XML
。AJAX
不是新的编程语言,而是一种将现有的标准组合在一起使用的新方式。它是一种技术方案,但并不是一种新技术。
它依赖的是现有的CSS/HTML/Javascript
,而其中最核心的依赖是浏览器提供的XMLHttpRequest
对象。这个对象为向服务器发送请求和解析服务器响应提供了流畅的接口,使得浏览器可以发出HTTP
请求与接收HTTP
响应,实现在页面不刷新的情况下和服务端进行数据交互。
本质上就是一种依赖于HTTP
技术提出的一种解决Web
数据交互的解决方案。
通过AJAX
可以在浏览器中向服务器发送异步请求,最大的优势为无刷新获取数据。
原生Ajax实现
本质上就是对浏览器提供的XMLHttpRequest
类进行一系列的操作。
请求状态
0
:请求未初始化,还没有调用open()
1
:请求已经建立,但是还没有发送,还没有调用send()
2
:请求已发送,正在处理中,通常现在可以从响应中获取内容头。
3
:请求在处理中;通常响应中已有部分数据可用了,没有全部完成。
4
:响应已完成;可以获取并使用服务器的响应了。
简单使用
1 | // 1.创建 XMLHttpRequest 对象 |
请求超时与网络异常处理
1 | const xhr = new XMLHttpRequest(); |
取消请求
1 | xhr.abort(); |
常见的Ajax请求方式
jQuery
1 | $.ajax({ |
Axios
1 | axios.defaults.baseURL = 'http://127.0.0.1:8000'; |
Fetch
1 | fetch('http://127.0.0.1:8000/fetch-server?vip=10', { |
跨域问题
跨越原因
一个网页向另一个不同域名/不同协议/不同端口的网页请求资源,这就是跨域。
跨域原因产生:在当前域名请求网站中,默认不允许通过ajax
请求发送其他域名。因为浏览器使用了同源策略。
同源策略
同源策略是Netscape
提出的一个著名的安全策略,现在所有支持JavaScript
的浏览器都会使用这个策略。同源策略是浏览器最核心也最基本的安全功能,如果缺少同源策略,浏览器的正常功能可能受到影响。可以说web
是构建在同源策略的基础之上的,浏览器只是针对同源策略的一种实现。
同源:协议、域名、端口号必须完全相同。违背同源策略就是跨域。
浏览器使用同源策略是为了保证用户的信息安全,防止恶意网站窃取数据,如果网页之间不满足同源要求,将不能:
- 共享
Cookie
、LocalStorage
、IndexDB
- 获取
DOM
AJAX
请求不能发送
解决方案
- 前端使用
jsonp
(不推荐使用) - 后台
Http
请求转发 - 后台配置同源
Cors
(推荐) - 使用
SpringCloud
网关 - 使用
nginx
做转发 (推荐)
Axios简介
目前前端最流行的ajax
请求库。react/vue
官方都推荐使用axios
发送ajax
请求。其特点主要包括:
- 基于
xhr(XMLHttpRequest) + promise
的异步ajax
请求库 - 浏览器端/
node
端都可以使用 - 支持请求/响应拦截器
- 支持请求取消
- 请求/响应数据转换
- 批量发送多个请求
创建实例
1 | const axios1 = axios.create({ |
调用顺序
调用axios()
并不是立即发送ajax
请求, 而是需要经历一个较长的流程:
请求拦截器2 => 请求拦截器1 => 发送ajax
请求 => 响应拦截器1 => 响应拦截器2 => 请求的回调(如果此时有多个请求和响应拦截器)
此流程是通过promise
串连起来的, 请求拦截器传递的是 config
, 响应拦截器传递的是response
。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
38
39
40
41
42
43
44
45
46
47
48
49// 设置请求拦截器 config 配置对象
axios.interceptors.request.use(function (config) {
console.log('请求拦截器 成功 - 1号');
//修改 config 中的参数
config.params = {
a: 100
};
return config;
}, function (error) {
console.log('请求拦截器 失败 - 1号');
return Promise.reject(error);
});
axios.interceptors.request.use(function (config) {
console.log('请求拦截器 成功 - 2号');
//修改 config 中的参数
config.timeout = 2000;
return config;
}, function (error) {
console.log('请求拦截器 失败 - 2号');
return Promise.reject(error);
});
// 设置响应拦截器
axios.interceptors.response.use(function (response) {
console.log('响应拦截器 成功 1号');
return response.data;
// return response;
}, function (error) {
console.log('响应拦截器 失败 1号')
return Promise.reject(error);
});
axios.interceptors.response.use(function (response) {
console.log('响应拦截器 成功 2号')
return response;
}, function (error) {
console.log('响应拦截器 失败 2号')
return Promise.reject(error);
});
//发送请求
axios({
method: 'GET',
url: 'http://localhost:3000/posts'
}).then(response => {
console.log('自定义回调处理成功的结果');
console.log(response);
});
默认配置
1 | // 默认配置 |
其他
请求/相应数据转换器
1 | // 请求转换器: 对请求头和请求体数据进行特定处理的函数 |
response与error的整体结构
1 | // response的整体结构 |
ajax fetch和axios的区别
ajax
本身是针对MVC
的编程,不符合现在前端MVVM
的浪潮基于原生的XHR
开发,XHR
本身的架构不够清晰,已经有了fetch
的替代方案。
fetch
fetch
号称是AJAX
的替代品,是在ES6
出现的,使用了ES6
中Promise
对象。
fetch
的代码结构比ajax
简单多了,但fetch
不是ajax
的进一步封装,而是原生js
,没有使用XMLHttpRequest
对象。
优点
- 符合关注分离: 没有将输入、输出和用事件来跟踪的状态混杂在一个对象里。
- 更加底层,提供的
API
丰富,是更好更方便的写法。 - 脱离了
XHR
,是ES
规范里新的实现方式。
缺点
fetch
只对网络请求报错,对400
、500
都当成成功的请求,需要封装去处理。fetch
默认不会带cookie
,需要添加配置项。fetch
不支持abort
(中止) 、不支持超时控制,使用setTimeout
及Promise.reject
实现的超时控制并不能阻止请求过程继续在后台运行,造成了量的浪费。fetch
不能原生检测请求的进度,而XHR
可以。
axios
Axios
是一个基于promise
的HTTP
库,可以在浏览器和Nodejs
中使用。
特性
- 从浏览器中创建
XMLHttpRequests
- 从
Node.js
中创建http
请求 - 支持
Promise API
- 拦截请求和响应
- 转换请求数据和响应数据
- 取消请求
- 自动转换
JSON
数据 - 客户端支持防御
XSRF