一、介绍
1.1什么是ajax
网页不刷新的情况下,发送http请求并得到响应。允许根据用户事件来更新部分页面内容
缺点:
1.没有浏览历史,不能回退
2.存在跨域问题(同源)
3.SEO不友好(爬虫不友好)
1.2原生ajax
ajax就是异步的js和xml。
1.3xml介绍
xml 可标记语言被设计用来传输和存储数据
xml和html类似,html是预定义标签,xml是自定义标签
1.4http协议
超文本传输协议,协议详细规定了浏览器和万维网服务器之间互相通信的规则。
二、发送ajax请求
2.1express安装和基本使用
安装node.js,在Webstorm中初始化后安装express
注:初始化是把最外层的包用终端打开初始化
npm init --yes
npm i express
*****如果require没有自动补齐
npm install -D tslib @types/node
基本使用
response和response Headers组合成给我们响应的页面
//引入express模块
const express = require('express');
//创建app应用对象
const app = express();
//创建路由规则
//request是请求报文
//response是响应报文
app.get('/',(request,response) => {
//设置响应
response.send('hello world');
});
//监听端口启动服务器
app.listen(3000,() => {
console.log("服务器启动成功")
})
2.2发送ajax请求的准备
发送ajax的GET请求准备
//引入express模块
const express = require('express');
//创建app应用对象
const app = express();
//创建路由规则
//request是请求报文
//response是响应报文
app.get('/server',(request,response) => {
//设置响应头 设置允许跨域
response.setHeader('Access-Control-Allow-Origin','*');
//设置响应体
response.send('hello world');
});
//监听端口启动服务器
app.listen(3000,() => {
console.log("服务器启动成功")
})
2.3发送ajax GET请求
代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
div {
width: 300px;
height: 150px;
border: 2px solid pink;
}
</style>
</head>
<body>
<button>点击发送请求1</button>
<div id ="div"></div>
</body>
</html>
<script>
var kk = document.getElementsByTagName('button')[0];
var div = document.getElementById('div');
kk.addEventListener('click',function (){
//创建对象
const xhr = new XMLHttpRequest();
//初始化 设置请求方法和url地址
xhr.open('GET','http://127.0.0.1:3000/server');
//发送请求
xhr.send();
//事件绑定 接受服务器返回的结果
//on when 当什么时候
//readstate 是 xhr中的属性 表示状态 0 1 2 3 4
//change 改变
xhr.onreadystatechange=function(){
//判断服务器响应了所有的结果
if(xhr.readyState === 4){
//判断服务器响应的状态码 2xx为成功
if(xhr.status>=200&&xhr.status<300){
console.log(xhr.status); //响应的状态码
console.log('------------------------');
console.log(xhr.statusText); //状态字符串
console.log('------------------------');
console.log(xhr.getAllResponseHeaders()); //所有响应头
console.log('------------------------');
console.log(xhr.response); //响应体
div.innerHTML=xhr.response;
}
}
}
})
</script>
如果报错存在跨域问题将设置跨域中的setHeader改为header
emmm 后来发现是Control这个单词写错了
设置请求参数
参数是加在url地址后面,用?分割传递多个参数使用&来连接
xhr.open('GET','http://127.0.0.1:3000/server?a=100&b=200&c=300');
2.4发送ajax POST请求
将之前的路由请求方式改为post
app.post(‘/server’,(request,response) => {
将open初始化参数改为POST
设置请求参数是在send发送请求中设置
xhr.send(‘a=100&b=200&c=300’);
2.5ajax 设置请求头信息
在初始化后发送请求前添加
//设置请求头 预定义 Content-Type设置请求体内容的类型 后面那一串参数查询字符串的类型
xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
//设置请求头 自定义 由于浏览器的安全机制需要我们加一个特殊的响应头
xhr.setRequestHeader('chongqing','gaodenghouwang');
由于浏览器的安全机制需要我们加一个特殊的响应头
response.setHeader('Access-Control-Allow-Headers','*');
此时出现报错 因为浏览器还会发一个OPTIONS的请求来校验检测我们这个头信息可用不可用
因为我们这个请求没有最终的结果 所以我们将创建路由中post改成all
app.all(‘/server’,(request,response) => {
2.6服务端响应JSON数据
模拟一下后端响应一个对象回去
//响应一个自定义的数据回去
const data = {
"chongqing":"gaodenghouwang"
}
//由于我们的send只能返回字符串或者Buffer 咱们做一个转换
const str = JSON.stringify(data);
//设置响应体
response.send(str);
我们发现数据简单但不美观
咱们前端方面转化一下 手动
//手动转化JSON为JavaScript对象数据
let data = JSON.parse(xhr.response);
div.innerHTML=data.chongqing;
需要在初始化前设置响应体数据为JSON 自动
//设置响应体数据为JSON
xhr.responseType='json';
两者均可效果一致
三、ajax关键问题
3.1安装nodemon自动重启工具
解决我们手动重启服务器的东西,让我们更好的偷懒摸鱼,安装nodemon
npm install -g nodemon
如果我们卡在安装窗口一直安装不上,我们配置淘宝镜像
// 配置npm代理来提高速度,设置淘宝镜像
npm config set registry https://registry.npm.taobao.org
// 查看配置是否成功
npm config get registry
再重新安装即可咱们关掉之前的服务 启动nodemon
注:我能们一定是把需要启动的js文件拖拽到终端 并且文件名不能带中文和空格
nodemon AJAX-JSON.js
3.2ie浏览器的缓存问题
ie存在缓存有可能会出现后端服务器不刷新的情况
我们只需要在请求地址拼接上现在的时间戳即可
3.3请求超时和网络异常处理
模拟一下后端出错返回了一个空数据,两秒后提示用户。
let str = ''; //模拟后端出错返回了一个空值
if(str==''){ //设置两秒的延时给 用户返回出错了
setTimeout(() => {
response.send('404找不到网页');
},2000)
}else {
response.send(str);
}
当然我们也可以在前端设置一秒后没得到返回的数据取消请求
xhr.timeout=1000;
canceled表示取消的意思,咱们还可以再前端设定请求超时的回调
//请求超时的回调
xhr.ontimeout=function (){
alert(‘请求超时请稍后重试’)
}
如果用户的网络出现异常咱们也可以在前端设置回调
//网络异常的回调
xhr.οnerrοr=function (){
alert(‘你的网络出了问题’)
}
咱们可以借助于chrome浏览器的offline功能模拟一下断网
3.4手动取消请求
xhr.abort(); //取消请求
<script>
let xhr = null;
var btn = document.querySelectorAll('button');
btn[0].addEventListener('click',function (){
xhr = new XMLHttpRequest();
xhr.open('GET','http://127.0.0.1:3000/delay');
xhr.send();
})
btn[1].addEventListener('click',function (){
xhr.abort();//由于咱们这个局部访问不到xhr所以在外部定义一下
})
</script>
3.5面对重复发送请求
为了给我服务器减小压力,用户发送一次请求未成功后再次发送请求会取消上一次请求
<script>
var btn = document.querySelector('button');
//获取元素对象
let xhr = null;
//检测是否在发送请求
let isSending = false;
btn.addEventListener('click',function (){
//如果正在发送则取消该请求,咱们就可以执行又一次请求
if (isSending) xhr.abort();
xhr = new XMLHttpRequest();
xhr.open('GET','http://127.0.0.1:3000/delay');
xhr.send();
isSending = true;
xhr.onreadystatechange=function (){
if(xhr.readyState===4){
//不在状态码判断成功的原因是 请求失败isSending一直处于true
isSending = false;
}
}
})
</script>
四、Jquery中发送ajax请求(bootcdn找插件)
后端代码
//引入express模块
const express = require('express');
//创建app应用对象
const app = express();
//创建路由规则
//延时设置
app.all('/axios-server',(request,response) => {
//设置响应头 设置允许跨域
response.setHeader('Access-Control-Allow-Origin','*');
response.setHeader('Access-Control-Allow-Headers','*');
const data = {chongqing:'gaodenghouwang'};
response.send(JSON.stringify(data));
});
//监听端口启动服务器
app.listen(3000,() => {
console.log("服务器启动成功")
})
4.1jquery发送get和post请求
引入Jquery https://www.bootcdn.cn/jquery/
<script>
$(function (){
$('button').eq(0).click(function (){
// url地址 参数 回调函数
$.get('http://127.0.0.1:3000/jquey-server',{a:100,b:200},function(response){
console.log(response);
})
})
})
</script>
发送get要求响应体返回json数据格式 再发送一个post请求
<script>
$(function (){
$('button').eq(0).click(function (){
// url地址 参数 回调函数
$.get('http://127.0.0.1:3000/jquey-server',{a:100,b:200},function(response){
console.log(response);
},'json'); //表示响应体是一个json格式数据
})
$('button').eq(1).click(function (){
// url地址 参数 回调函数
$.post('http://127.0.0.1:3000/jquey-server',{a:100,b:200},function(response){
console.log(response);
});
})
})
</script>
4.2jquery发送ajax请求
如果不使用dataType:‘json’转化为json数据的话接受到的就是一个字符串
<script>
$(function (){
$('button').eq(2).click(function (){
$.ajax({
//请求的url地址
url:'http://127.0.0.1:3000/jquery-server',
//请求参数
data:{a:100,b:200},
//请求的响应体返回json数据格式
dataType:'json',
//成功时的回调
success:function (response){
console.log(response);
},
//设置延时返回错误的回调
timeout:2000,
error:function (){
console.log('error');
}
//设置头信息
headers:{
a:200,
b:300
}
})
})
})
</script>
4.3axios发送get和post请求
发送GET请求
axios的返回结果是基于Promise对象
<script>
var btn = document.getElementsByTagName('button');
btn[0].addEventListener('click',function (){
axios.get('http://127.0.0.1:3000/axios-server',{
//url 参数
params:{
a:100,
b:200
},
//设置请求头
headers:{
name:'houwang',
age:18
}
}).then(value => {
console.log(value)
})
})
</script>
data就是响应体自动解析之后的结果
发送POST请求
btn[1].addEventListener('click',function (){
// url data请求体 ,其他配置
axios.post('http://127.0.0.1:3000/axios-server',{
admin:'root',
password:123456
},{
//url 参数
params:{
a:100,
b:200
},
//设置请求头
headers:{
name:'houwang',
age:18
}
}).then(value => {
console.log(value)
})
})
请求体的话不是发了一个url查询字符串的形式而是一个json格式字符串
4.4axios发送ajax请求
btn[2].addEventListener('click',function (){
axios({
// 请求方法
methods:'POST',
//url
url:'http://127.0.0.1:3000/axios-server',
//url参数
params:{
a:100,
b:200
},
//请求头信息
headers:{
name:'houwang',
age:18
},
//请求体参数
data:{
admin:'root',
password:123456
}
}).then(response => {
//响应体状态码
console.log(response.status);
//响应字符串
console.log(response.statusText);
//响应头
console.log(response.headers);
//响应体
console.log(response.data);
})
})
4.5使用fetch函数发送ajax请求
fetch函数是属于全局对象的,可以直接调用,返回的结果是一个Promise对象
很显然这个响应体的结果并不是我们想要的,我们想要的结果可以调用一下这里面的text或者json方法拿到
<script>
var btn = document.getElementsByTagName('button');
btn[0].addEventListener('click',function (){
//url 请求对象 请求参数直接后缀加
fetch('http://127.0.0.1:3000/fetch-server?a=100&b=200',{
//请求方法
method:'POST',
//请求头
headers:{
name:'houwang'
},
//请求体
body:'username=admin&password=admin'
}).then(response => {
// return response.text(); //拿到的一个字符串 我们服务器返回的是一个json
return response.json();
//这里如果直接打印会得到一个Promise对象没有值,所以返回出去让下一个then方法来打印
}).then(response => {
console.log(response)
})
})
</script>
五、跨域问题
5.1同源策略小案例
同源:协议,域名,端口必须完全相同
违背同源策略就是跨域
注:直接启动这个页面运行是不能获取后端数据的 需要在浏览器输入127.0.0.1:3000/tongyuan
<script>
var btn = document.querySelector('button');
btn.addEventListener('click',function (){
const xhr = new XMLHttpRequest();
//因为满足同源策略 所以url可以简写
xhr.open("GET",'/data');
xhr.send();
xhr.onreadystatechange = function (){
if(xhr.readyState === 4 ){
if(xhr.status>=200&&xhr.status<300){
console.log(xhr.response);
}
}
}
})
</script>
5.2JSONP跨域
JSONP就是借助于script来实现跨域的
这个应该才是src一个完整的书写方式
咱们这个kuayu.js返回的资源就是Response的内容,再由我们的script标签做一个解析再把这个结果渲染给页面
这就是JSOP的原理
我堂堂一个script标签给你发请求你给我返回一个这玩意儿,此时控制台是报错的
js引擎是解析不了的,所以我们一个返回一个js代码
不难看出后端给我们返回的是一个函数调用
然后我们的前端正好有这个函数,js就直接解析了所以后端返回的数据直接渲染在页面上
这就是JSONP实现跨域的原理
5.3JSONP实践
我们做一个用户名输入框,不管输入什么返回咱们都新增一个p标签提示用户名以存在,并且输入框变红
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div>
用户名:<input type="text">
</div>
</body>
</html>
<script>
var input = document.getElementsByTagName('input')[0];
var username = ''
//onblur事件 当失去焦点时候执行
input.onblur = function (){
username = this.value;
//创建一个script标签
let script = document.createElement('script');
//向我们本地的服务器发送请求
script.src = 'http://127.0.0.1:3000/jsonp';
//在我们的body下插入这个标签
//appendChild() 在当前节点的子节点末尾新增一个节点
document.body.appendChild(script);
}
function kk(data){
var div = document.querySelector('div');
let p = document.createElement('p');
div.appendChild(p);
p.innerHTML=`${username}这个${data.message}`;
input.style.border='1px solid red';
}
</script>
可以看出后端给我们返回的是一个函数调用和一个参数
5.4JQuery发送JSONP请求
做一个按钮,点击按钮发送请求,返回咱们的 框框里面
虽然我发送请求时callback给的一个?,但在实际发送请求时这个参数是有值的
我们需要把这个callback的值做为函数调用的函数去拼接字符串
也就是说jquery已经是注册了这样的一个函数,只要回来的时候返回的是这个函数 的调用。
咱们的前端就可以对这个代码做一个处理
此时我们的控制台已经有结果了
只需要渲染到前端页面即可
<script>
$(function (){
$('button').eq(0).click(function (){
//必须跟参数callback=? 这是一个固定写法
$.getJSON('http://127.0.0.1:3000/jquery-JSONP?callback=?',function (data){
// console.log(data);
$('div').html(`
名字:${data.name},
<br>
城市:${data.city},
`)
})
})
})
</script>
5.5CORS响应头实现跨域
CORS是官方的跨域解决方案,不需要在客户端做任何得到特殊处理操作,完全在服务器中进行处理,支持get和post请求。实现跨域只需要加上一个响应头即可。
response.setHeader('Access-Control-Allow-Origin','*');
<script>
var btn = document.getElementsByClassName('button');
btn[0].addEventListener('click',function (){
//创建对象
const xhr = new XMLHttpRequest();
//初始化
xhr.open('GET','http://127.0.0.1:3000/cors');
//发送请求
xhr.send();
//处理返回结果
xhr.onreadystatechange = function (){
if(xhr.readyState === 4){
if(xhr.status>=200&&xhr.status<300){
console.log(xhr.response);
}
}
}
})
</script>