接口与ajax
## 2.接口开发规范
### 2.1 开发模式
- 开发模式
~~~js
前后端分离:前端渲染模式
前端:写页面,请求后端数据,在前端使用html+数据拼接渲染
ajax,axios
后端:接口开发,返回不是html文件,返回json数据
前后端不分离:后端渲染模式
前端:写页面html+css+js
后端:使用模块ejs,把前端写好的页面返回给用户,在后端使用模板语法进行数据拼接
~~~
- ==后端渲染模式(前后端不分离):html和数据拼接都是在后端处理的,(后端程序员干的)==
- ==前端渲染模式(前后端分离):后端定义接口给前端开发者提交json数据,在前端进行html的渲染和数据的拼接==
- 用Express开发可以返回**html、css、img等这类的数据**。 也可以返回json数据: 只提供json数据的Express服务指的就是==接口开发== ,这些数据的返回和之前所讲述==http协议有着密不可分的关系==,只要正确定义路由、使用合理的请求就能拿到结果,但一个好的接口开发工程师应该遵守RESTful API规范。
### 2.2 RESTful api规范
#### 2.2.1 简介
- RESTful规范,是目前一种比较流行的互联网软件设计规范
- 这个规范约束的就是:
- ==路由地址应该如何定义==
- ==返回的json接口数据应该如何规范==
- 好处:使开发者在进行独立开发或协作开发更能标准,以达到行业的统一。它结构清晰、符合标准、易于理解、扩展方便,越来越多的开发者遵守这种规范
- ==常用规范方法==
- GET:SELECT 获取资源
- POST:CREATE 、INSERT INTO 创建、添加资源
- PUT:UPDATA 更新资源
- DELETE:DELETE 删除资源
#### 2.2.2 定义路由地址
- 以学生为例:只要是数据都包含的操作:增,删,改,查
| 功能 | 方法 | 路由(接口) | 传参 |
| ------------ | ------ | -------------------------- | ------------------------------------------- |
| 增加一个学生 | POST | /student | req.body:name,age,sex..... |
| 删除一个学生 | DELETE | /student?id=1 | req.query : 删除学生的id |
| 更新一个学生 | PUT | /student | req.body:id改的学生,提交修改信息 |
| 查询一个学生 | GET | /student?id=1 /student/:id | req.query:获取id req.params |
| 查询一组学生 | GET | /students?size=10 | req.query: size个数 |
#### 2.2.3 json接口规范
- 错误的数据
~~~js
{
status:500, //状态码
msg:"参数不对,错误信息"
}
~~~
- 正确的数据
- 增
~~~js
{
status:200, //状态码
msg:"添加成功",
result:"添加成功元素的id"
}
~~~
- 删除
~~~js
{
status:200, //状态码
msg:"删除成功"
}
~~~
- 改
~~~js
{
status:200, //状态码
msg:"更新成功"
}
~~~
- 查
~~~js
查一个:
{
status:200, //状态码
msg:"查询成功",
result:{
name:"",
age:"",
...
}
}
查一组:
{
status:200, //状态码
msg:"查询成功",
result:[{name:""...},{name:""...},{name:""...},{name:""...}],
rows:总条数
page:当前页码
pageTotal:总页数
}
~~~
#### 2.2.4 根据RESTful 进行接口开发
- 使用express脚手架生成接口项目:express --view=ejs 项目名
- 进入项目,安装依赖包 npm i
- 创建student.js模块文件,在routes目录中
- 定义模块化代码(写接口)
~~~js
//查询一个学生
router.get('/student', function(req, res, next) {
let {id} = req.query;
//接口开发:返回json数据
if(!id){
res.send({
status:500,
msg:"请传递需要查询的学生id"
});
return;
}
//查询--去数据库中进行查询操作
res.send({
status:200,
msg:"查询成功",
result:{
name:"张三",
age:18,
height:180
}
})
});
~~~
- 在入口文件app.js中引入路由
- 启动项目
### 2.3 接口说明书(会看)
- 接口根地址:http://loaclhost:300
- 接口地址:/student
- 功能:查询一个学生
- 请求:get
- 数据的提交格式:json,查询字符串
- 参数
| 名称 | 必需 | 类型 | 说明 |
| ---- | ---- | ------ | -------- |
| id | true | number | 学生的id |
- 拼接实例:http://loaclhost:300//student?id=1
- 响应示例
~~~js
{
"status":200,
"msg":"查询成功",
"result":{"name":"张三","age":18,"height":180}
}
~~~
- 字段说明
## ==3.ajax(前端用的)==
### 3.1 介绍
- ==ajax:Asynchronous JavaScript And XML(异步的JavaScript和XML)== 2005
~~~xml
xml:之前的数据表现形式,现在用json
<note>
<to>George</to>
<from>John</from>
<heading>Reminder</heading>
<body>Don't forget the meeting!</body>
</note>
~~~
- ==作用:代替浏览器地址栏向服务器发起请求,异步请求后端数据,完成页面的局部更新==
- ==使用场景:实现页面局部更新==
- 传统请求方式(浪费资源)
- ==通过浏览器地址栏向服务器发起请求,页面是同步的==
- ==阻塞代码的执行,会更新整个页面,造成资源浪费,影响速度==
![05-1传统请求](\img\05-1传统请求.jpg)
- ajax请求方式
==ajax相对于浏览器发起请求和接收响应的代理人,实现在不影响用户浏览页面的的情况下,局部更新页面数据,从而提高用户体验==
![05-2ajax请求方式](\img\05-2ajax请求方式.jpg)
- 概念:
- 是一种用于创建快速动态网页的技术。
- Ajax 是一种在无需重新加载整个网页的情况下,能够更新部分网页的技术。
- ==通过在后台与服务器进行少量数据交换,Ajax 可以使网页实现异步更新。==
- 这意味着可以在不重新加载整个网页的情况下,对网页的某部分进行更新。
### 3.2 原生ajax
==掌握:ajax请求过程,ajax状态码的值,get和post的区别==
#### ==3.2.2 实现步骤==
##### 1) 创建对象
- ==创建ajax对象:XMLHttpRequest==
```js
let xhr =new XMLHttpRequest();
```
##### 2) 建立连接
- 和后台服务器建立连接:open
- ==语法: xhr.open(method,url,async)==
- 参数:
- method:请求方式get / post/delete / put
- url:请求地址
- async:是否异步,默认为true
```js
xhr.open('GET','bendi.txt',true);
```
##### 3) 发送请求
- 发送请求:send
- ==语法:xhr.send(string)==
- 参数:
- string请求参数,仅用与post请求,传递请求参数
```js
xhr.send();
```
##### 4) 响应数据
- 获取服务器响应给客户端的数据
- ==xhr.onreadystatechange : 兼听服务器响应过来数据==
- 当请求被发送到服务器时,每当 readyState 改变时,就会触发 onreadystatechange 事件
- xhr.readyState : 服务器响应状态
- 在创建ajax对象,配置ajax对象,发送请求,以及接收完服务器端响应数据,这个过程中的每一个步骤都会对应一个数值,这个数值就是ajax状态值。
包含的状态值:
(1)0:请求未初始化,还没有调用open
(2)1:请求已经建立,但是还没有发送send
(3)2:请求已经发送 已经执行了send
(4)3:请求正在处理中,通常响应中已经有部分数据可以用了
(5)==4:响应已经完成,可以获取并使用服务器的响应==
- ==xhr.status : 服务器响应状态码==
- 无论AJAX访问是否成功,由HTTP协议根据所提交的信息,服务器所返回的HTTP头信息代码,该信息使用“ajax.status”所获得;(由数字1XX,2XX三位数字组成)
常见状态码:200,304,404,500
```js
ajax.onreadystatechange = function(){
//[1:创建ajax对象,2:建立连接,3:发送请求服务器正在处理,4:服务器处理完成并返回响应包]
if(ajax.readyState == 4){
if(ajax.status == 200){ //成功
oAjax.responseText //服务器响应的结果
}
}
}
```
##### 5) 实例
- 后端接口
~~~js
//4.响应
app.get("/demo",(req,res)=>{
//响应一个页面
res.sendFile(path.join(__dirname,"01 ajax请求数据的过程.html"));
})
app.get("/ajax",(req,res)=>{
res.send({
status:200,
msg:"数据请求成功,ahhahahha"
})
})
~~~
- 前端请求
~~~js
//1.获取元素
let oBtn = document.querySelector("button");
let oP = document.querySelector("p");
//2.点击按钮的时候,请求后端数据
oBtn.onclick = function(){
//1.创建请求对象
let xhr = new XMLHttpRequest();
/*2.建立连接 :xhr.open(method,url,async)
参数:
method:请求方式(不区分大小写) get post delete put
url:请求地址
async:是否异步,默认是true
*/
xhr.open("get","http://localhost:3000/ajax",true);
//3.发送请求
xhr.send();
//4.监听数据响应
xhr.onreadystatechange = function(){
/* xhr.readyState状态一变化就会触发这个事件
0:未调用open
1:建立连接,没有send
2:发送了请求
3:服务器已经接受到请求,正在处理
4:服务器已完成响应,并且将响应结果返回
*/
console.log(xhr.readyState);
if(xhr.readyState == 4){ //服务器已完成响应,并且将响应结果返回
console.log(xhr.status); //状态码 200:成功 404 500
if(xhr.status == 200){ //请求数据成功
//获取到响应的数据 xhr.responseText
console.log(xhr.responseText); //所有从服务器获取的数据都是字符串、
let data = JSON.parse(xhr.responseText);
oP.innerHTML = data.msg;
}
}
}
}
~~~
#### 3.1.3 ajax get与post请求
- get和post的操作是一模一样的,请求参数传递上有区别
##### 1) get
- 语法
```js
xhr.open("get","http://localhost:3000/ajax?参数列表",true);
```
==get请求参数拼接到url的地址后面,"url?key1=v1&key2=v2"==
- 案例
```js
xhr.open("get","http://localhost:3000/ajax?username=web&password=123",true);
```
##### 2) post
==post请求参数是放在请求体里面==
- 语法1:
```js
xhr.open("post",url,async);
xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded")
xhr.send(string) // string:post参数 查询字符串格式key1=v1&key2=v2
```
- 语法2:
```js
xhr.open("post",url,async);
xhr.setRequestHeader("Content-Type","application/json")
xhr.send(string) // string:post参数 json
```
- 代码案例
```js
xhr.open("post", "http://localhost:3000/ajax", true);
//3.发送请求 xhr.send(string)
//3.1 传递查询字符串格式
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xhr.send("username=web&password=123");
//3.2 传递json
xhr.setRequestHeader("Content-Type", "application/json");
xhr.send(JSON.stringify({username:"web",password:"123"}));
```
### ==3.2 jQuery的ajax==
- 都是依赖于 XMLHttpRequest 封装出来的。
- http://libs.baidu.com/jquery/1.11.1/jquery.min.js
#### 3.2.1 $.get(了解)
- 语法:
```js
$.get(URL,callback)
```
- 代码案例
```js
$("button").click(function () {
/*
语法:$.get(url,successcallback)
作用:进行get请求
参数:
url:请求地址,参数直接拼接在url后面
successcallback:请求成功时调用的回调函数
*/
$.get("http://localhost:3000/ajax?username=web", (res) => {
//这个函数能执行,一定是做好了判断,readyState == 4 , status=200
//jQuery处理了返回的数据,字符串-转化对象
//请求成功,会将结果传递给res
console.log(res);
})
})
```
#### 3.2.2 $.post(了解)
- 语法:
```js
$.post(URL,data,callback)
data:
请求参数 {key:value,key:value}
```
- 代码案例
```js
$("button").click(function () {
/*
语法:$.post(url,data,successcallback)
作用:进行post请求
参数:
url:请求地址,参数直接拼接在url后面
data:请求参数,{key1:value,key2:value}
successcallback:请求成功时调用的回调函数
*/
let data = {username:"Web",password:123}
$.post("http://localhost:3000/ajax",data, (res) => {
//这个函数能执行,一定是做好了判断,readyState == 4 , status=200
//jQuery处理了返回的数据,字符串-转化对象
//请求成功,会将结果传递给res
console.log(res);
$("p").html(res.msg);
})
})
```
#### ==3.2.3 $.ajax==
- 语法
```js
$.ajax({
*url:"请求地址",
type:"请求方法,默认是get get post delete put",
data:"请求参数 {}",
dataType:"jsonp", //ajax处理跨域
*success:(res)=>{}, 成功的时候的回调,结果在res中接收
error:(err)=>{}失败时的回调
})
```
- 代码案例
```js
$("button:eq(0)").click(function () {
/*
$.ajax({
*url:"请求地址",
type:"请求方法,默认是get get post delete put",
data:"请求参数 {}",
dataType:"jsonp", //ajax处理跨域
*success:(res)=>{}, 成功的时候的回调,结果在res中接收
error:(err)=>{}失败时的回调
})
*/
$.ajax({
url: "http://localhost:3000/ajax",
type: "get",
data: { username: "Web", password: "123" },
success: (res) => {
console.log(res);
$("p").html(res.msg)
}
})
})
$("button:eq(1)").click(function () {
$.ajax({
url: "http://localhost:3000/ajax",
type: "post",
data: { username: "Web", password: "123" },
success: (res) => {
console.log(res);
$("p").html(res.msg)
}
})
})
```
## ==4.跨域(面试)==
### 4.1 跨域介绍
- 同源策略:浏览器规定,只能访问同源(自己)的东西
- 跨域概念:==通过ajax进行http请求时,只要违反同源策略就会产生跨域==
- 什么情况会产生跨域:
- 协议不同会跨域:http https
- 域名不同:http://www.taobao.com http://www.jd.com
- 端口号不同:http://www.jd.com:8080 http://www.jd.com:3000
- 跨域种类
![5-5跨域种类](/img/5-5跨域种类.png)
- 跨域错误
![5-6跨域错误](/img/5-6跨域错误.png)
### 4.2 CORS解决跨域
- ==CORS:跨域资源共享==
- ==跨域:后端代码不让前端跨域==
- ==解决跨域:通过cors这个后端技术,设置响应头,允许前端跨域就可以了==
![5-7cors](/img/5-7cors.jpg)
- Access-Control-Allow-Origin
- 语法
~~~js
res.header('Access-Control-Allow-Origin', '*');
~~~
- 描述:默认情况下只能用域发送ajax请求。此属性可以设置 哪个来源( url )可以请求 。常常设置为 *
- Access-Control-Allow-Methods
- 语法
~~~js
res.header('Access-Control-Allow-Methods', '*');
~~~
- 描述:默认情况下,CORS 仅支持客户端发起 GET、POST 请求。如果客户端希望通过 PUT、DELETE 等方式请求服务器的资源,则需要在服务器端,通过 Access-Control-Alow-Methods来指明实际请求所允许使用的 HTTP 方法。
- 代码
~~~js
//冗余代码,封装(中间件)
app.use((req, res, next) => {
//后端:允许当前来源进行ajax请求访问,允许任何来源
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Methods", "*");
next(); //一定要next,要不然就会卡住
})
app.get("/demo1", (req, res, next) => {
//后端:允许当前来源进行ajax请求访问
// res.header("Access-Control-Allow-Origin","http://127.0.0.1:5500");
res.send("我是demo1,我被访问了");
})
app.get("/demo2", (req, res, next) => {
//后端:允许当前来源进行ajax请求访问
// res.header("Access-Control-Allow-Origin","http://127.0.0.1:5500");
res.send("我是demo2,我被访问了");
})
~~~
- ==总结:如果后端进行接口开发(定义路由返回json数据),就应该配置跨域响应头==
### 4.3 cors中间件解决跨域
- 下载包
~~~js
npm i cors
~~~
- 引入
~~~js
const cors = require("cors")
~~~
- 匹配中间件(所有路由的前面)
~~~js
app.use(cors()); //使用cors中间件,允许跨域
~~~