Appearance
前后端交互
学习目标
- 【了解】前后端分离的概念
- 【了解】HTTP协议
- 【掌握】Ajax的使用
- 【掌握】Fetch的基本使用
- 【掌握】接口测试工具的使用
- 【了解】Restful接口风格
- 【掌握】Axios的使用
前后端分离的概念
在当代web应用的开发中,前端和后端作为2个独立的岗位愈加区分开了工作职责,前端负责视图开发,后端负责数据开发,前后端通过一种"方式"实现交互,最终完成整个web应用。
这种开发模式的好处显而易见:
- 提高开发效率: 前后端开发人员可是同时开发, 互不影响
- 提高复用性: 后端通过统一的API提供数据, 这样可以同时为web前端/app前端/微信端提供数据
Http协议
我们刚才提到了前后端通过一种“方式”来进行交互,这种方式便是Http协议,Http是一种网络协议, 规定了web服务器与浏览器之前的交互方式, 是一种一问一答协议。
常见的http请求包括get请求和post请求:
- get请求是从服务器上获取数据,可以直接通过浏览器输入URL来获得。
- post请求是向服务器传送数据,无法通过浏览器URL直接实现。
- get传送的数据量较小,不能大于2KB。
- post请求的数据是放在请求体中的,存放的数据量不受限制。
- get请求携带的参数直接暴露,安全性非常低。
- post请求安全性相对较高。
对于http请求来说,可能会有多种响应结果,http状态码就是用来表示响应结果的:
- 1xx:指示信息--表示请求已接收,继续处理。
- 2xx:成功--表示请求已被成功接收、理解、接受。
- 3xx:重定向--要完成请求必须进行更进一步的操作。
- 4xx:客户端错误--请求有语法错误或请求无法实现。
- 5xx:服务器端错误--服务器未能实现合法的请求。
常见的状态码:
- 200 OK:客户端请求成功。
- 400 Bad Request:客户端请求有语法错误,不能被服务器所理解。
- 401 Unauthorized:请求未经授权,这个状态代码必须和WWW-Authenticate一起使用。
- 403 Forbidden:服务器收到请求,但是拒绝提供服务。
- 404 Not Found:请求资源不存在,举个例子:输入了错误的URL。
- 500 Internal Server Error:服务器发生不可预期的错误。
Ajax的使用
了解了http请求后,我们现在应该关注一件事,如何通过JS代码来实现一个具体的http请求,首先我们来学习第一种方法,也是最常用的方法——AJAX。
AJAX = Asynchronous JavaScript And XML.
AJAX基于浏览器内建的 XMLHttpRequest 对象实现,Ajax 允许通过与Web 服务器交换数据来异步更新网页。这意味着可以更新网页的部分,而不需要重新加载整个页面。
- 网页中发生一个事件(页面加载、按钮点击)
- 由 JavaScript 创建 XMLHttpRequest 对象
- XMLHttpRequest 对象向 web 服务器发送请求
- 服务器处理该请求
- 服务器将响应发送回网页
- 由 JavaScript 读取响应
- 由 JavaScript 执行正确的动作(比如更新页面)
现在我们把上述步骤转化为JS代码,这里需要明确一点,完成上面的流程我们还需要一个服务器接口,在当前课程阶段,我们可以找一个公共接口来实现,例如:API接口
我们现在调用 这个接口,将返回的中文内容渲染到页面上。
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<h1>今天的励志是:</h1>
<button onclick="init()">点我励志</button>
<script>
function init() {
let xhr = new XMLHttpRequest()
xhr.onreadystatechange = function () {
if (this.readyState == 4 && this.status == 200) {
document.querySelector('h1').innerHTML =JSON.parse(this.responseText).data.zh
}
}
xhr.open("GET", "https://api.vvhan.com/api/en")
xhr.send()
}
</script>
</body>
</html>
这里我们需要关注的是onreadystatechange事件,它会监听readyState的状态值变化:
- 0: 请求未初始化
- 1: 服务器连接已建立
- 2: 请求已接收
- 3: 正在处理请求
- 4: 请求已完成且响应已就绪
当 readyState
为 4
,status
为 200
时,我们可以认为这个http响应就绪,便可以获得服务端的数据了。
Ajax是JS中最为常见的异步场景,可以使用大家Promise进行进一步封装,大家思考一下上述案例如何利用Promise来进行优化呢?
Fetch的基本使用
除了Ajax,javascript还提供了一个全局方法fetch可以实现http请求,它返回一个Promise对象,通过2次调用.then方法可以获取到数据内容。上文中的案例可以使用fetch来进行改写:
js
function init() {
fetch("https://api.vvhan.com/api/en").then(res=>{
return res.json()
}).then(res=>{
document.querySelector('h1').innerHTML = res.data.zh
})
}
在实际工作开发中,我们更多地使用Ajax来进行前后端交互,fetch的兼容性相对较差。
接口调试工具
我们刚才演示了使用JS代码来获取接口数据,但很多场景下,使用JS代码来测试接口相对麻烦,这时我们可以使用接口调试工具来实现,这类工具的使用方法基本一致,例如postman,apizza 以及更好支持中文的ApiPost等。
Restful接口风格
前后端分离的协作模式要求前端在调用接口,后端在设计接口时尽量保持一致,RESTful便是一种当前最流行的接口设计风格,主要包括以下方面:
资源路径(URL)
标准的RESTful API中, 每个资源路径对应一个唯一的资源
所以规定网址中不能有动词, 只能有名词, 并且一般来说为复数.
示例
HTTP动词(Method)
对于资源, 一般有4个操作, CURD(增/删/改/查)
- GET: 从服务器获取资源(一项或多项)
- POST: 在服务器新建一个资源
- PUT: 在服务器更新资源, 服务器返回完整的属性
- DELETE: 从服务器删除资源
- PATCH: 在服务器更新资源, 服务器只返回更新的属性
示例
- POST /articles -- 创建文章内容
- GET /articles/1 -- 获取主键id为1的文章
过滤信息(query-string)
当服务端需要返回的数据很多时, 服务器不可能全部返回
此时, 我们可以在客户端携带过滤信息, 比如: 分页信息
示例
- ?page=1 -- 第一页的信息
- ?offset=10&per_page=10 -- 每页10条, 偏移10
状态码(Status-code)
服务端返回的信息, 用来告诉客户端操作结果
状态码 含义 说明 200 OK 操作成功, 并返回数据 201 CREATED 新建成功 204 NO CONTENT 删除成功 400 BAD REQUEST 请求语法错误 403 Forbidden 请求没有权限的资源 404 NOT FOUND 没有找到请求的资源 错误信息(Error)
如果状态码是4xx或者5xx, 需要告诉客户端对应的错误信息. 以JSON格式返回
返回结果(Result)
针对不同的操作, 服务需要返回的结果应该符合这样的规范
- GET /collections -- 返回资源列表(数组)
- GET /collections/:id -- 返回单个资源 eg. /collections/1
- POST /collections -- 返回新生成的资源
- PUT /collections/:id -- 返回资源的完整属性
- PATCH /collections/:id -- 返回被修改的属性
- DELETE /collections/:id -- 返回204状态码+空文档
当然,实际接口的表现并非和RESTful完全一致,让前后端更好地沟通交流是接口设计的最终原则。
Axios的使用
Axios 是一个基于 promise 的 HTTP 库,可以用在浏览器和 node.js 中。是当前最为流行的http库,它之所以流行是得益于它的以下特性:
- 从浏览器中创建 XMLHttpRequests
- 从 node.js 创建 http 请求
- 支持 Promise API
- 拦截请求和响应
- 转换请求数据和响应数据
- 取消请求
- 自动转换 JSON 数据
- 客户端支持防御 XSRF
我们可以把axios理解为对AJAX的封装,使用起来会高效很多,一起来尝试看,
首先在当前页面中引入axios:
html
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
这样我们可以在全局获得一个axios函数,尝试使用它来发送一个请求:
js
axios.get('https://api.vvhan.com/api/en')
axios是基于Promise实现的,响应的结果保存到了Promise中,所以可以通过then方法中回调传入的参数来获取结果。
我们刚才发送get请求的方式是一种简写形式,完整的写法是这样的:
js
axios({
method: 'GET',
url: 'https://api.vvhan.com/api/en',
}).then((res) => console.log(res))
通过传入配置对象的形式来确认发送请求的类型,以及请求的URL,我们现在就对这个配置选项来做全面的学习。
配置选项
method
method是创建请求时的方法,常见的有get post put patch delete等,如果没有指定,默认为get。
url
url是用于请求的服务器url地址,这个配置选项是必需的,其他配置选项都有默认值。
baseURL
通过设置baseURL,可以提取url中重复的部分,例如:设置baseURL:https://api.vvhan.com/api
url选项设置为/en
即可。
data
data是请求中携带的数据。只适用于post put patch方法。data中携带数据的格式由后端来定义,前端根据接口文档来设置即可,一般即为普通对象。
timeout
请求超时的时间,如果请求超过了设定的timeout那么请求便会被中断。
params
发送get请求时携带的查询参数还可以通过params选项的形式传递,例如https://api.vvhan.com/api/en?type=sj
中携带的参数可以写成params选项:
js
axios({
method: 'GET',
url: 'https://api.vvhan.com/api/en',
params:{
type:'sj'
}
})
headers
headers中可以配置请求的请求头信息,在登录认证中一般会在请求头中携带token信息。
响应对象
发送一个axios请求后,返回的结果有固定的结构,现在对这个结构加以说明:
js
{
// `data` 表示服务器返回的具体数据
data: {},
// `status` 来自服务器响应的 HTTP 状态码
status: 200,
// `statusText` 来自服务器响应的 HTTP 状态信息
statusText: 'OK',
// `headers` 服务器的响应头信息
headers: {},
// `config` 是为请求提供的配置信息 即是我们传入的配置选项
config: {},
// `request` 是 发送请求的XHR对象
request: {}
}
默认值
可以通过指定默认值的形式来给axios请求添加配置选项。
js
axios.defaults.baseURL = 'https://api.example.com';
axios.defaults.timeout = 3000;
每个axios请求会有默认值的baseURL和timeout
拦截器
http请求在发送和响应的过程可以被axios拦截器处理。在拦截器中可以进行额外的逻辑处理。
js
// 添加请求拦截器
axios.interceptors.request.use(function (config) {
// 在发送请求之前做些什么 这里有一个最常见的前端场景 就是给请求头中添加token信息
config.headers.Authorization=AUTH_TOKEN
return config;
}, function (error) {
// 对请求错误做些什么
return Promise.reject(error);
});
// 添加响应拦截器
axios.interceptors.response.use(function (response) {
// 对响应数据做点什么 如果我们只需要响应的数据内容 可以返回response.data
return response.data;
}, function (error) {
// 对响应错误做点什么
return Promise.reject(error);
});
通过以上对axios的学习,你能否自己来实现一个建议版的axios呢?