作者主页:仙女不下凡
前言介绍:以下 内容都是我个人对于前端知识的总结,会定期更新欢迎持续关注!
欢迎点赞 收藏 ⭐留言 如有错误敬请指正!
学习视频地址:【尚硅谷】3小时Ajax入门到精通
AJAX
全称为Asynchronous JavaScript And XML
,就是一部的JS
和XML
。通过AJAX
可以在浏览器中向服务器发送一部请求,最大的优势:无刷新获取数据。AJAX
不是新的编程语言,而是一种将现有的标准组合在一起使用的刷新方式。
XML
可扩展标记语言XML
被设计用来传递和存储数据XML
和HTML
类似,不同的是HTML
中都是预定义标签,而是XML
中没有预定义标签,全都是自定义标签,用来表示一些数据。
比如name='孙悟空'; age=18; gender='男'
,用XML
表示。
<student>
<name>孙悟空name>
<age>18age>
<gender>男gender>
student>
思考: 为什么提到XML
因为AJAX
发送请求返回的数据格式形式就是XML
格式,然后通过JavaScript
转换成js
对象,但是现在已经被JSON
取代了。
用JSON表示:
{"name":"孙悟空","age":"18","gender":"男"}
AJAX
的优点: ❶可以无需刷新页面而与服务器进行通信 ❷允许你根据用户事件(click/change等)来更新部分页面内容。
AJAX
的缺点: ❶没有浏览历史,不能回退 ❷存在跨域问题(同源) ❸SEO
不友好。
HTTP
协议[超文本传输协议]: 该协议详细规定了浏览器和万维网服务器之间互相通信的规则。
⏭请求报文(重点是格式与参数)
行 GET /s?ie=utf-8 HTTP/1.1
头 Host: atguigu.com
Cookie: name=guigu
Content-type: application/x-www-form-urlencoded
User-Agent: chrome 8.3
空行
体 空
行 POST /s?ie=utf-8 HTTP/1.1
头 Host: atguigu.com
Cookie: name=guigu
Content-type: application/x-www-form-urlencoded
User-Agent: chrome 8.3
空行
体 username=admin&password=admin
⏭响应报文
行 HTTP/1.1(协议) 200(响应) ok
头
Content-type: text/html; charset=utf-8
Content-length: 2048
Content-encoding: gzip
空行
体 ...
学习AJAX
使用之前先了解一个基本框架express
框架,它是一个基于Node
平台的web
应用开发框架,也是node
第三方模块。
express
框架的基本使用,语法格式如下
/1.引入express/
const express = require('express');
/2.创建路由规则/
const app = express();
/3.创建路由规则 request是对请求报文的封装(自定义), response是对响应报文的封装(自定义)/
app.get('/',(request,response) => {
/设置响应/
response.send('HELLO EXPRESS')
});
/4.监听端口启动服务/
app.listen(8000, ()=>{ console.log("服务器已经启动, 8000端口监听中...")})
GET
请求在url
中传参,例如:http://127.0.0.1:8000/server?a=100&=200&c=300
其中参数名为a、b、c
参数分别为100、200、300
/GET.html文件/
<body>
<button>点击发送请求button>
<div id="result">div>
<script>
const btn = document.getElementByTagName('button')[0];
btn.onclick = function({
/1.创建对象/
const xhr = new XMLHttpRequest();
/2.初始化 设置请求方法和url/
xhr.open('GET','http://127.0.0.1:8000/server?a=100&=200&c=300'); //暂时http://127.0.0.1:8000不可以省略;
/3.发送请求/
xhr.send();
/4.事件绑定 处理服务器端返回结果/
xhr.onreadystatechange = function(){
}; /readystate是xhr对象中的属性, 表示状态, 1 2 3 4 5,5种不同状态/
})
script>
body>
服务端server.js
文件
const express = require('express');
const app = express();
app.get('/server',(request,response) => {
response.sedHeader('Access-Control-Allow-Origin','*'); //设置响应头, 设置允许跨域
response.send('HELLO EXPRESS'); //设置响应
});
app.listen(8000, ()=>{ console.log("服务器已经启动, 8000端口监听中...") })
下面为GET.html
文件中的内容,页面效果当点击发送请求后,页面向服务器发送post
请求,且携带参数,post
请求的参数一般写在在send()
请求体中,示例代码如下
<body>
<button>点击发送请求button>
<div id="result">div>
<script>
const btn = document.getElementByTagName('button')[0];
btn.onclick = function({
const xhr = new XMLHttpRequest();
xhr.open('POST','http://127.0.0.1:8000/server');
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); //post特有,设置请求提类型;
xhr.setRequestHeader('name','zhangsan'); /一般把用户身份校验信息放到这里/
xhr.send('a=100&b=200&c=300'); //post请求设置请求参数, 参数格式也可以是a:100&b:200c:300;
xhr.onreadystatechange = function(){
//判断
if(xhr.readyState === 4){
if(xhr.status>=200 && xhr.status<300){
result.innerHTML = xhr.response; //处理服务端返回的结果, 这里的result是id;
}
}
};
})
script>
body>
该文件为服务端-server.js
文件,接收GET.html
文件发送的请求处理后给GET.html
返回响应内容,示例代码如下
const express = require('express');
const app = express();
app.post('/server',(request,response) => {
response.sedHeader('Access-Control-Allow-Origin','*'); //设置响应头, 设置允许跨域/
response.send('HELLO EXPRESS'); //设置响应/
});
app.listen(8000, ()=>{ console.log("服务器已经启动, 8000端口监听中...") })
创建路由规则时可以接收任意请求类型,即post、get
等都可以接收,写法如下
app.all('/server',(request,response) => {
response.sedHeader('Access-Control-Allow-Origin','*'); //允许跨域;
/设置响应头, *表示所有类型的信息都可以接受/
response.sedHeader('Access-Control-Allow-Headers','*');
response.send('HELLO EXPRESS');
});
在学习响应JSON
数据时,不知道你是否产生过一些疑问,为什么要用JSON
类型,客服端与服务器端之前转来转去有什么意义呢?我在该篇文章中找到了相应比较容易理解的解释:json的存在意义(json和String的区别)
<body>
<button>点击发送请求button>
<div id="result">div>
<script>
const btn = document.getElementByTagName('button')[0];
btn.onclick = function({
const xhr = new XMLHttpRequest();
xhr.open('GET','http://127.0.0.1:8000/json-server');
xhr.send();
xhr.onreadystatechange = function(){
if(xhr.readyState === 4){
if(xhr.status>=200 && xhr.status<300){
let data = JSON.parse(xhr.response); /在这里接收到服务器传过来的JSON字符串, 手动转换/
result.innerHTML = data.name; /若不转换JSON字符串data.name不能用, 未来大量数据无法处理/
}
}
};
})
script>
body>
服务端代码如下
app.all('/json-server',(request,response) => {
response.sedHeader('Access-Control-Allow-Ori','*');
response.sedHeader('Access-Control-Allow-Ori','*');
const data = { name:'zhangsan' };
let str = JSON.stringify(data); //对对象进行字符串转换
response.send('HELLO EXPRESS'); /设置响应/
});
服务端代码无变化,所以这里只写页面代码
<body>
<button>点击发送请求button>
<div id="result">div>
<script>
const btn = document.getElementByTagName('button')[0];
btn.onclick = function({
const xhr = new XMLHttpRequest();
xhr.responseType = 'json'; /设置响应体数据类型, 自动转换/
xhr.open('GET','http://127.0.0.1:8000/json-server');
xhr.send();
xhr.onreadystatechange = function(){
if(xhr.readyState === 4){
if(xhr.status>=200 && xhr.status<300){
/因借助responseType属性所以这里直接.name就是zhangsan/
result.innerHTML = xhr.response.name;
}
}
};
})
script>
body>
加时间戳Date.now()
解决IE缓存的问题,示例代码如下
<body>
<button>点击发送请求button>
<div id="result">div>
<script>
const btn = document.getElementByTagName('button')[0];
const result = document.getElementById('result');
btn.onclick = function({
const xhr = new XMLHttpRequest();
/加时间戳Date.now()解决IE缓存的问题/
xhr.open('GET','http://127.0.0.1:8000/ie?t='+Date.now());
xhr.send();
xhr.onreadystatechange = function(){
if(xhr.readyState === 4){
if(xhr.status>=200 && xhr.status<300){
result.innerHTML = xhr.response;
}
}
};
})
script>
body>
服务端代码如下
app.all('/ie',(request,response) => {
response.sedHeader('Access-Control-Allow-Ori','*');
response.sedHeader('Access-Control-Allow-Ori','*');
response.send('HELLO IE'); /设置响应/
});
请求超时或网络异常服务器没有返回数据时,需要处理,语法格式如下
const xhr = new XMLHttpRequest();
xhr.timeout = 2000; //超时设置, 超时时长为2s
xhr.ontimeout = function(){
//这里写页面响应的内容
}
xhr.open('GET','http://127.0.0.1:8000/ie');
xhr.send();
xhr.onreadystatechange = function(){};
调用abort()
方法就可以取消请求,示例代码如下
<body>
<button>点击发送button>
<button>点击取消button>
<script>
const btns = document.getElementByTagAll('button');
let xhr = null;
btns[0].onclick = function({
xhr = new XMLHttpRequest();
xhr.open('GET','http://127.0.0.1:8000/ie');
xhr.send();
})
btns[1].onclick = function(){
xhr.abort(); /取消请求/
}
script>
body>
思考: 若向服务器中重复发送相同的不必要请求,其实我们只请求一次就可以,这种情况怎么办呢?下面我们就通过标识变量去解决这个问题,示例代码如下
<body>
<button>点击发送button>
<script>
const btn = document.getElementByTagName('button');
let xhr = null;
let isSending = false; /标识变量/
btn.onclick = function({
if(isSending)xhr.abort(); //如果正在发送, 则取消该请求, 创建一个新的请求
xhr = new XMLHttpRequest();
isSending = true; //修改标识变量的值;
xhr.open('GET','http://127.0.0.1:8000/ie');
xhr.send();
xhr.onreadystatechange = function(){
if(xhr.readyState === 4) isSending = false;
}
})
script>
body>
下面演示在jquery
框架中发送ajax
请求的方法,示例代码如下
<body>
<button class="btn">GETbutton>
<button class="btn">POSTbutton>
<button class="btn">通用型方法ajaxbutton>
<script>
$('button').eq(0).click(function(){
$.get('http://127.0.0.1:8000/jquery-server', {a:100,b:200}, function(data){
console.log(data); //控制台结果为{name:'zhangsan'}
},'json'); /这里标识响应体为json格式数据/
})
$('button').eq(1).click(function(){
$.post('http://127.0.0.1:8000/jquery-server', {a:100,b:200}, function(data){
console.log(data); //控制台结果为{name:'zhangsan'}
},'json')
});
/通用型发送ajax请求/
$('button').eq(2).click(function(){
$.ajax({
url: 'http://127.0.0.1:8000/jquery-server',
data: {a:100,b:200}, /参数/
type: 'GET', /类型/
dataTaye: 'json', /响应体数据类型/
success: function(data){}, /成功的回调/
timeout: 2000, /超时时间/
error: function(data){}, /失败的回调/
headers: {c:300,d:400}, /头信息/
})
})
script>
body>
服务器端代码
app.all('/jquery-server',(request,response) => {
response.sedHeader('Access-Control-Allow-Origin','*');
response.sedHeader('Access-Control-Allow-Headers','*');
const data = {name:'zhangsan'};
response.send(JSON.stringify(data)); /设置响应/
});
总结: 在jquery
框架中通用型ajax
发送请求功能性更加强一些,但是以上两种方式代码更加简洁,可以根据实际的应用选择具体写法。
使用Axios
发送ajax
请求时,需要安装Axios
或者直接npm install axios
引入。
<head>
<script src="引入的axios的文件包">script> //这里也可以直接用npm install axios直接安装
head>
<body>
<button>GETbutton>
<button>POSTbutton>
<button>AJAXbutton>
<script>
const btns = document.querySelectorAll('button');
axios.defaults.baseURL = 'http://127.0.0.1:8000'; /配置baseURL, 下面的地址就可以省略了/
btns[0].onclick = function(){
axios.get('/axios-server',{
params: {id:100, vip:7}, /url参数/
headers: {name:'lisi',age:25}, /请求头信息/
....
}).then(value=>{}); /它的请求是在.then()中处理的,跟ajax不一样/
}
btns[1].onclick = function(){
axios.get('/axios-server',{这是请求体},{
params: {id:200, vip:9}, /url参数/
headers: {name:'lisi',age:18}, /请求头信息/
}).then(value=>{}); /它有三个参数, 另外它的请求是在.then()中处理的,跟ajax不一样/
}
btns[2].onclick = function(){
axios({
method: 'GET', /请求类型/
url: '/axios-server',
params: {}, /url参数/
headers: {}, /头信息/
data: {} /请求体信息/
}).then(response=>{
console.log(response.status); /响应状态码/
console.log(response.statusText); /响应状态字符串/
console.log(response.data); /响应体/
})/它的格式跟jquery通用型ajax相似, 非常简洁,请求响应结果也是在.then()中处理/
}
script>
body>
服务端代码如下
app.all('/axios-server',(request,response) => {
response.sedHeader('Access-Control-Allow-Origin','*');
response.sedHeader('Access-Control-Allow-Headers','*');
const data = {name:'zhangsan'};
response.send(JSON.stringify(data)); /设置响应/
});
fetch()
属于全局对象,可以直接调用,返回结果是promise
对象,在前端发送Ajax
中使用axios
的非常多,但是使用fetch()
使用的比较少,在这里fetch()
作为了解进行学习。
//该项目中已经npm install axios直接安装axios
<body>
<button>AJAX请求button>
<script>
const btns = document.querySelector('button');
btns.onclick = function(){
fetch.get('http://127.0.0.1:8000/fetch-server?id=3',{ //url参数直接写在后面
method: 'POST', /请求方法/
headers: {}, /请求头/
body: 'username=zhangsan&password=admin', /请求体, 注意请求体格式/
}).then(response=>{
return response.json(); /这里需要用return返回响应结果并且在下一个.then()中处理/
//如果服务器返回的不是json字符串用return response.text()处理
}).then(response=>{/这里的response就是响应结果{name:'zhangsan'}, 别和上面的response混淆呦/});
}
script>
body>
服务端代码如下
app.all('/fetch-server',(request,response) => {
response.sedHeader('Access-Control-Allow-Origin','*');
response.sedHeader('Access-Control-Allow-Headers','*');
const data = {name:'zhangsan'};
response.send(JSON.stringify(data)); /设置响应/
});
同源策略: 最早由Netscape
公司提出,是浏览器的一种安全策略。
同源: 指协议、域名、端口号必须完全相同,违背同源策略就是跨域。
下面用一段代码演示什么是同源发送请求,点击按钮后/home
页面获取到/data
中的数据,启动服务器后找到打开http://127.0.0.1:9000/home
页面呈现如下图
服务器端代码如下
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("服务器已经启动....") });
.html
页面代码如下
<body>
<h1>.html页面h1>
<button>AJAX请求button>
<script>
const btns = document.querySelector('button');
btns.onclick = function(){
const xhr = new XMLHttpRequest();
/因为这里是同源策略, 所以url可以简写/
xhr.open('GET', '/data');
xhr.onreadystatechange = function(){
if(xhr.readyState === 4){
if(xhr.status>=200&&xhr.status<300) console.log(xhr.response);
}
}
}
script>
body>
非同源(跨域): 指协议、域名、端口号其中有一样或多样不相同就是跨域。但是非同源会有很多限制。
【1】无法读取非同源网页的Cookie、LocalStorage 和 IndexedDB
;
【2】无法接触非同源网页的DOM
;
【3】无法向非同源地址发送AJAX
请求。
在实际的项目中我们常常遇到跨域的情况,为了解决这些问题,所以下面讨论两种"跨域"的解决方案:JSONP
与CORS
(其实还有其他的办法)。
JSONP
怎么工作呢?JSONP
利用script
标签的跨域能力来发送请求。
下面用一段实例代码演示JSONP
的实现原理,下面代码运行地址flie://src/index.html
但是引入的是http
协议的http://127.0.0.1:8000/jsonp-server
所以为跨域。
<body>
<div id="result">div>
<script>
function handle(data){
const result = document.querySelectorId('result');
result.innerHTML = data.name;
}
script>
<script src="http://127.0.0.1:8000/jsonp-server">script>
body>
//服务器代码
app.all('/jsonp-server',(request,response) => {
const data = {name:'zhangsan'};
let str = JSON.stringify(data);
response.end(`handle(${str})`);
});
JSONP
缺点: 但是JSONP
是一个非官方的跨域解决方案,而且只支持get
请求。
下面用一个简单的业务需求来演示原生jsonp
的使用。
需求: ❶当在input
输入框中输入失去焦点之后发送ajax
请求❷将跨域服务器中的内容响应到页面上。
<body>
用户名:<input type="text" id="username">
<p>p>
<script>
const input = document.querySelector('input');
const p = document.querySelector('p');
function handle(data){
p.innerHTML = data.msg;
}; //声明handle函数, 与服务器保持一致
input.onblur = function(){
let username = this.value;
const script = document.createElement('script'); /1.创建script标签/
script.src = 'http://127.0.0.1:8000/check-username'; /2.设置script标签/
document.body.appendChild(script); /3.将script标签插入文档/
};
script>
body>
//服务器代码
app.all('/check-username',(request,response) => {
const data = {msg:'用户名已经存在'};
let str = JSON.stringify(data);
response.end(`handle(${str})`); //服务器调用handle函数
});
好了以上代码就实现了跨域的jsonp
请求。
<body>
<button>发送jsonp请求button>
<div id="result">div>
<script>
$('btton').eq(0).click(function(){
/固定jsonp传参数用callback, jquery中的发送的callback?直接就转换成参数了,可以自己运行一下/
$.getJSON('http://127.0.0.1:8000/jquery-jsonp-server?callback=?', function(data){
$('#result').html('名称: ${data.name}
')
})
});
script>
body>
//服务器代码
app.all('/jquery-jsonp-server',(request,response) => {
const data = {name:'zhangsan'};
let str = JSON.stringify(data);
let cb = request.query.callback; /这样就取到上面自动转换的callback参数了/
response.end(`${cb}(${str})`);
});
CORS
(跨域资源共享): 是官方的跨域解决方案,默认支持get
与post
请求(需要其他请求方式自己可以设置这里不展开),跟上面JSONP
不同的是CORS
是通过设置一个响应头来告诉浏览器(上面其实我已经用到啦),该请求允许跨域,浏览器收到该响应就会对响应放行。
CORS
的使用: 主要是服务器端的设置router.get("/testAJAX",function(req,res){})
。
<body>
<button>发送jsonp请求button>
<div id="result">div>
<script>
const button = document.querySelector('button');
function handle(data){
p.innerHTML = data.msg;
}; //声明handle函数, 与服务器保持一致
button.onclick = function(){
const xhr = new XMLHttpRequest;
xhr.open("GET","http://127.0.0.1:8000/cors-server");
xhr.send();
xhr.onreadystatechange = function(){
if(xhr.readyState === 4){
if(xhr.status>=200 && xhr.status<300){
response.setHeader("Access-Control-Allow-Origin","*"); /这就可以啦/
}
}
}
};
script>
body>
//服务器代码
app.all('/cors-server',(request,response) => {
response.send(hello cors);
});
其实除了Access-Control-Allow-Origin
响应头以外还有其他的响应头,有需要的可以自行了解一下。