第一章:原生 AJAX
1.1 AJAX 简介
AJAX 全称为 Asynchronous JavaScript And XML,就是异步的 JS 和 XML。
通过 AJAX 可以在浏览器中向服务器发送异步请求,最大的优势:无刷新获取数据。
AJAX 不是新的编程语言,而是一种将现有的标准组合在一起使用的新方式。
1.2 XML 简介
XML 可扩展标记语言。
XML 被设计用来传输和存储数据。
XML 和 HTML 类似,不同的是 HTML 中都是预定义标签,而 XML 中没有预定义标签,
全都是自定义标签,用来表示一些数据。
比如说我有一个学生数据:
name = "孙悟空" ; age = 18 ; gender = "男" ;
用 XML 表示:
<student>
<name>孙悟空</name>
<age>18</age>
<gender>男</gender>
</student>
现在已经被 JSON 取代了。
用 JSON 表示:
{"name":"孙悟空","age":18,"gender":"男"}
1.3 AJAX 的特点
优点
-
可以无需刷新页面而与服务器端进行通信。
-
允许你根据用户事件来更新部分页面内容。
缺点
-
没有浏览历史,不能回退
-
存在跨域问题(同源)
-
SEO 不友好爬虫获取不到数据)
1.4 HTTP协议
超文本传输协议,详细规定了浏览器和万维网服务器之间互相通信的规则
请求报文
注意:GET请求报文请求体为空
URL里的参数解析
响应报文
请求体
1.5 Express框架
安装包:npm init --yes
安装express框架:npm i express
使用express框架
设置允许跨域: 在步骤3添加
response.setHeader('Access-Control-Allow-Origin','*');
响应一个页面:sendFile需要写绝对路径
response.sendFile(__dirname+'/index.html');
response.end()与response.send()区别在于 response.end()不会加特殊的响应头
第二章:AJAX的使用
2.1 核心对象
XMLHttpRequest,AJAX 的所有操作都是通过该对象进行的。
2.2 使用步骤
先在script标签里先获取dom元素(button等)然后给元素绑定事件并在事件函数里:
-
1、创建XMLHttpRequest对象
const xhr = new XMLHttpRequest ();
-
2、设置请求信息:请求方法和 url [可选:设置url参数]
xhr.open( method, url );
xhr.open('GET','http://127.0.0.1:8080/server?a=100&b=200&c=300');
//还可以设置请求头,一般不设置
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
-
3、发送请求 xhr.send();
xhr.send(body)
注意:get 请求不传 body 参数,只有 post 请求使用`
-
4、接收响应:事件绑定 处理服务端返回的结果
-
xhr.responseXML 接收 xml 格式的响应数据
-
xhr.responseText 接收文本格式的响应数据。如:const text = xhr.responseText;
-
xhr.status //状态码
-
xhr.status Text //状态字符串
-
xhr.getAllResponseHeaders() //所有响应头
-
xhr.response //响应体
-
xhr.onreadystatechange = function (){
//4.1判断(4表示:服务端返回了所有的结果)
if(xhr.readyState === 4){
//4.2 判断响应状态码 2xx 即为成功
if(xhr.status >= 200 && xhr.status <300){
//4.3 处理结果 行 头 空行 体
result.innerHTML = xhr.response
}
}
响应状态码
-
1xx(临时响应)
表示临时响应并需要请求者继续执行操作的状态代码。 -
2xx (成功)
表示成功处理了请求的状态代码。 -
3xx (重定向)
表示要完成请求,需要进一步操作。 通常,这些状态代码用来重定向。 -
4xx(请求错误)
这些状态代码表示请求可能出错,妨碍了服务器的处理。 -
5xx(服务器错误)
这些状态代码表示服务器在尝试处理请求时发生内部错误。 这些错误可能是服务器本身的错误,而不是请求出错。
常见状态码:
-
200 - 服务器成功返回网页
-
403 (禁止) 服务器拒绝请求
-
404 - 请求的网页不存在
-
500 (服务器内部错误) 服务器遇到错误,无法完成请求。
-
503 - 服务不可用
-
505 (HTTP 版本不受支持) 服务器不支持请求中所用的 HTTP 协议版本。
post请求设置请求体(参数)
post请求设置请求头(预定义、自定义)
2.3 服务端响应JSON数据
后台对响应体data 对象 ( 如{name: 'wdt', age: 20} ) 进行字符串转换
let str = JSON.stringify(data);
在前台手动将字符串转换为对象
let data = JSON.parse (xhr.response );
在前台自动将获取的服务端字符串转换成对象:
//设置响应体数据的类型
xhr.responseType = 'json';
2.4 nodemon自动重启工具
安装:npm install -g nodemon
启动服务: nodemon server.js
2.5 IE缓存问题
问题:在一些浏览器中(IE),由于缓存机制的存在,ajax 只会发送的第一次请求,剩
余多次请求不会在发送给浏览器而是直接加载本地缓存中的数据。数据不是服务器返回的最新数据
解决方式:浏览器的缓存是根据 url 地址来记录的,所以我们只需要修改 url 地址,在URL后面加参数,例如时间戳,即可避免缓存问题。实际工作中不需要自己加,工具会做好
xhr.open("get",'http://127.0.0.1:8000/ie?t='+Date.now());
2.6 AJAX 请求状态
xhr.readyState 可以用来查看请求当前的状态
https://developer.mozilla.org/zh-CN/docs/Web/API/XMLHttpRequest/readyState
-
0: 表示 XMLHttpRequest 实例已经生成,但是 open()方法还没有被调用。未初始化最开始的默认值
-
1: 表示 open()方法调用完毕,send()方法还没有被调用,仍然可以使用 setRequestHeader(),设定 HTTP请求的头信息。
-
2: 表示 send()方法已经执行,并且头信息和状态码已经收到。
-
3: 表示正在接收服务器传来的 body 部分的数据。服务端已返回部分的数据
-
4: 表示服务器数据已经完全接收,或者本次接收已经失败了
2.7 ajax请求超时或网络异常
超时:timeout、ontimeout
网络异常:onerror
2.8 ajax取消请求:abort()
2.9 AJAX请求重复发送问题解决
增加一个标识变量:
第二章:jQuery中的AJAX
2.1 get请求
$.get(url,[data],[callback],[type])
-
url : 请求的URL地址
-
data : 请求携带的参数,比如
-
callback : 载入成功时回调函数,比如function(data)
-
type : 设置响应体返回内容格式,xml, html, script, json, text, _default
2.2 post请求
$.post(url,[data],[callback],[type])
-
url : 请求的URL地址
-
data : 请求携带的参数
-
callback : 载入成功时回调函数
-
type : 设置返回内容格式,xml, html, script, json, text, _default
2.3 jQuery通用方法发送请求
ajax方法参数为一个对象,由对象属性设置请求参数
$.ajax({
//url(给谁发)
url: 'http://127.0.0.1:8000/jquery-server',
//参数
data: {a:100, b:200},
//请求类型
type: 'GET',
//响应体结果类型设置
dataType: 'json',
//超时时间
timeout: 2000,
//成功的回调
success:function(data){
console.log(data);
},
//失败的回调
error:function(data){
console.log('出错啦!');
},
//请求头信息
headers:{
c:300,
d:400
}
});
2.4 Axios发送AJAX请求
数据返回和处理:jQuery使用的是回调函数,而axios是基于promise(then函数)
安装:npm install axios
baseURL: 对路径做简化
//配置baseURL
axios.defaults.baseURL = 'http://127.0.0.1:8000';
2.4.1 get请求
axios#get(url[,config])
//配置baseURL
...
axios.get('/axios-server',{
//url参数
params: {
id:100,
vip:7
},
//请求头信息
headers:{
name: 'wdt',
age: 20
}
}).then(value => {
console.log(value);
});
2.4.2 post请求
axios#post(url[,data[,config]])
第一个参数是url,第二个参数是请求体(发送的不是url查询字符串的形式,而是json格式的字符串作为数据传递),第三个参数是其他配置
//配置baseURL
...
axios.get('/axios-server',{
username:'admin',
password:'admin'
},{
//url参数
params: {
id:200,
vip:9
},
//请求头信息
headers:{
height: 160,
weight: 100
}
}).then(value => {
console.log(value);
});
2.4.3 通用方法--Axios函数发送AJAX请求
axios()里面直接传一个对象
ajax({
//请求方法
method: 'POST',
//url
url: '/axios-server',
//url参数
params: {
vip:10,
level:30
},
//请求头信息
headers:{
a:300,
b:400
}
//请求体参数
data: {
username:'admin',
password:'admin'
}
}).then(response => {
console.log(response);
//响应状态码
console.log(response.status);
//响应状态字符串
console.log(response.statusText);
//响应头信息
console.log(response.headers);
//响应体
console.log(response.data);
})
2.4.3 fetch函数发送AJAX请求
fetch函数属于全局对象,可以直接调用,返回的结果是promise对象,这个promise会在请求响应后被resolve,并传回Response对象
fetch( input [, init] );
-
input
定义要获取的资源,这可能是:URL 或 一个Request对象
-
init
可选的配置对象,包括所有对请求的设置,可选的参数有
method、headers、body(可以是Blob,BufferSource,FormData,URLSearchParams或USVString对象,注意GET或HEAD方法的请求不能包含body信息)、mode、credentials等
//可设置url参数
fetch('http://127.0.0.1:8000/fetch-server?vip=10', {
//请求方法
method: 'POST',
//请求头信息
headers:{
name:'wdt'
}
//请求体
body: 'username=admin&password=admin'
}).then(response => {
//响应体结果不能直接获取需要return
//如果服务端返回的是字符串
//return response.text();
//如果服务端返回的是json
return response.json();
}).then(response => {
console.log(response);
})
第三章:跨域
3.1 同源策略
同源策略(Same-Origin Policy)最早由Netscape公司提出,是浏览器的一种安全策略。
同源:当前网页的url和AJAX请求目标资源的url两者之间的 **协议、域名、端口号 **必须完全相同。
-- AJAX默认遵循同源策略:不满足同源策略没法直接发送AJAX请求
-- 违背同源策略就是跨域。
- 同源案例:页面资源和服务端返回的数据(这里是'用户数据')都是从9000端口来的
index.html :
<script>
const btn = document.querySelector('button');
btn.onclick = function(){
const x = new XMLHttpRequest();
//这里因为是满足同源策略的, 所以 url 可以简写
x.open("GET",'/data');
//发送
x.send();
//
x.onreadystatechange = function(){
if(x.readyState === 4){
if(x.status >= 200 && x.status < 300){
console.log(x.response);
}}}}
</script>
server.js :
const express = require('express');
const app = express();
app.get('/home', (request, response)=>{
//响应一个页面
response.sendFile(__dirname + '/index.html');
});
app.get('/data', (request, response)=>{
response.send('用户数据');
});
app.listen(9000, ()=>{
console.log("服务已经启动...");
});
3.2 如何解决跨域
3.2.1 JSONP
JSONP(JSON with Padding),是一个非官方的跨域解决方案,纯粹凭借程序员的聪明
才智开发出来,只支持 get 请求。
JSONP实现原理
在网页有一些标签天生具有跨域能力,比如:img link iframe script标签。
JSONP 就是利用 script 标签的跨域能力来发送请求的。
服务端返回结果的形式是一个函数的调用,而这个函数的实参是我们想给客户端返回的结果数据,这个函数前端必须要提前声明,这就是jsonp实现跨域的原理,即返回函数调用,并且把参数放函数里,让前端的函数去处理
原生JSONP实践
在前端中输入用户名,判断用户已存在:
<html>
...
<body>
用户名: <input type="text" id="username">
<p></p>
<script>
//获取 input 元素
const input = document.querySelector('input');
const p = document.querySelector('p');
//声明 handle 函数
function handle(data){
input.style.border = "solid 1px #f00";
//修改 p 标签的提示文本
p.innerHTML = data.msg;
}
//绑定事件
input.onblur = function(){
//获取用户的输入值
let username = this.value;
//向服务器端发送请求 检测用户名是否存在
//1. 创建 script 标签
const script = document.createElement('script');
//2. 设置标签的 src 属性 给谁发请求
script.src = 'http://127.0.0.1:8000/check-username';
//3. 将 script 插入到文档中,否则浏览器不会向远端发送请求
//把script标签插到body标签的最后
document.body.appendChild(script);
}
</script>
</body>
</html>
后端代码:
app.all('/check-username',(request,response) => {
const data = {
exist: 1,
msg: '用户名已存在'
};
//将数据转换为字符串
let str = JSON.stringify(data);
//返回结果
response.end(`handle(${str})`);
});
JSONP的使用
-
1.动态的创建一个 script 标签
var script = document.createElement("script");
-
2.设置 script 的 src,设置回调函数
script.src = "http://localhost:3000/testAJAX?callback=abc"; function abc(data) { alert(data.name); };
-
3.将 script 添加到 body 中
document.body.appendChild(script);
-
4.服务器中路由的处理
router.get("/testAJAX" , function (req , res) { console.log("收到请求"); var callback = req.query.callback; var obj = { name:"孙悟空", age:18 } res.send(callback+"("+JSON.stringify(obj)+")"); });
jQuery 中的 JSONP
使用jQuery发送JSONP请求时,url后面一定要补个参数callback,而且callback一定要固定写法
callback=?
callback在写的时候是个问号,但是在实际发送中是有值的。服务端可以接收到,收到后把callback这个参数的值作为调用的函数去拼接字符串。也就是说jQuery以及注册了这样的函数,从服务端回来后返回的是这个函数的调用,然后前端就可以对数据进行处理了。
...
//引进jQuery,借助BootCDN
<script crossorigin="anonymous" src='https://cdn.bootcss.com/jquery/3.5.0/jquery.min.js'></script>
</head>
<body>
<button>点击发送 jsonp 请求</button>
<div id="result">
</div>
<script>
//绑定事件
$('button').eq(0).click(function(){
//发送jsonp请求 url 参数callback function
$.getJSON('http://127.0.0.1:8000/jquery-jsonp-server?callback=?', function(data){
//在回调函数中对数据进行处理
$('#result').html(`
名称: ${data.name}<br>
校区: ${data.city}
`)
});
});
</script>
服务端代码:
app.all('/jquery-jsonp-server',(request,response) => {
const data = {
name: '尚硅谷',
city: ['北京','上海','深圳']
};
//将数据转换为字符串
let str = JSON.stringify(data);
//接收url中的callback参数
let cb = request.query.callback;
//返回结果
response.end(`${cb}(${str})`);
});
3.2.2 CORS
https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Access_control_CORS
CORS(Cross-Origin Resource Sharing),跨域资源共享。CORS 是官方的跨域解决方
案,它的特点是不需要在客户端做任何特殊的操作,完全在服务器中进行处理,支持
get 和 post 请求。跨域资源共享标准新增了一组 HTTP 首部字段(响应头),允许服务器声明哪些
源站通过浏览器有权限访问哪些资源
CORS工作原理
CORS 是通过设置一个响应头setHeader()来告诉浏览器,该请求允许跨域,浏览器收到该响应
以后就会对响应放行。
CORS的使用
主要是服务器端的设置:
router.get("/testAJAX" , function (req , res) {
//通过 res 来设置响应头,来允许跨域请求的网页url,一般写*,表示所有网页均可发送请求
//res.set("Access-Control-Allow-Origin","http://127.0.0.1:3000");
res.set("Access-Control-Allow-Origin","*");
res.send("testAJAX 返回的响应");
});
HTTP 响应标头(首部)字段
-
Access-Control-Allow-Origin
设置源:即哪些网页可以给服务端发请求
-
Access-Control-Expose-Headers
设置服务端返回的结果哪些头部信息可以暴露
-
Access-Control-Max-Age
设置预请求的结果能被缓存多久,加个时间后,每次请求直接去请求而不会做预检查
-
Access-Control-Allow-Credentials
跨域请求时是否可携带验证信息,如cookie之类
-
Access-Control-Allow-Methods
设置访问资源时允许使用的请求方法,默认post和get都可以,如果想要发生delete等其他请求的方法,需要加设置,比如加*,表示任何请求方法都可以运行请求
-
Access-Control-Allow-Headers
发送的请求加了自定义请求头时,需要在响应结果中加入允许的响应头的信息,比如*,表示允许客户端在发送请求时可以发送任意的请求头,可以是预定义的也可以是自定义的。