一、Ajax简介
AJAX 是一种在无需重新加载整个网页的情况下,能够更新部分网页的技术。
二、学习前的准备
需要对js的基础语法有一定的了解
三、后端的准备工作
这里我们不使用Django这种比较大的框架来实现,我们只用Node.JS
,可以下载安装一下这个框架express
,再安装一个插件nodemon
在当前目录下执行下面的命令
npm init --yes
npm i express
在当前的目录下创建一个app.js
// 引入express
const express = require('express');
const res = require('express/lib/response');
// 创建应用对象
const app = express();
// 可以接受任意类型的请求,这里也可以设置为post或者get
// 路由卸载第一个参数内
app.all('/server', (request, response) => {
// 设置响应头可以接受任何的响应头可以接受跨域
response.setHeader('Access-Control-Allow-Origin', '*');
response.setHeader('Access-Control-Allow-Header', '*');
// 设置响应体,也就是返回的数据
response.send('HELLO Ajax');
})
// 可以接受任意类型的请求
app.all('/json', (request, response) => {
// 设置响应头 设置允许跨域
response.setHeader('Access-Control-Allow-Origin', '*');
response.setHeader('Access-Control-Allow-Header', '*');
const data = {
name : 'atguigu',
age : 18
};
// 将对象数据转换为JSON字符串
let str = JSON.stringify(data)
// 设置响应体
response.send(str);
})
app.all('/time', (request, response) => {
response.setHeader('Access-Control-Allow-Origin', '*');
const data = {
name : 'atguigu',
age : 18
};
let str = JSON.stringify(data)
setTimeout(
function () {
response.send(str)
},3000)
})
// 设置监听的端口号
app.listen(8000, () => {
console.log("服务已经启动,8000端口正在监听中");
})
然后我们启动应用
node app.js
四、原生JS-Ajax
发送get请求
<!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>
<style>
#result {
width: 200px;
height: 100px;
border: solid 1px #90b;
}
</style>
<body>
<button>点击发送请求</button>
<div id="result"></div>
<script>
const btn = document.querySelector('button');
// 给按键绑定事件
btn.onclick = function(){
// 创建对象
const xhr = new XMLHttpRequest();
// 初始化,设置请求方法和URL
xhr.open('GET','http://127.0.0.1:8000/server');
// get的参数 ?a=100&b=200&c=300
// 发送
xhr.send()
// 事件绑定,处理服务端返回的结果
// readystate 是xhr对象中的属性,标示状态0 1 2 3 4
xhr.onreadystatechange = function(){
// 判断(服务端返回了所有的结果)
if(xhr.readyState === 4){
// 判断响应状态码,2xx都是成功
if(xhr.status >= 200 && xhr.status<300){
// 处理结果 行 头 空行 体
// 获取状态码和状态响应字符
console.log(xhr.status);
// 获取状态响应字符串
console.log(xhr.statusText);
// 获取状态头
console.log(xhr.getAllResponseHeaders);
// 2.响应体
console.log(xhr.response);
}
}
}
}
</script>
</body>
</html>
发送post请求
发送post请求的方法和get是很相似的,只是xhr的方法改为post
result.addEventListener('click',function(){
var xhr = new XMLHttpRequest();
xhr.open('POST','http://127.0.0.1:8000/server');
// 设置请求头的信息
xhr.setRequestHeader('Content-type','text/plain')
xhr.setRequestHeader('name','atue')
xhr.send();
xhr.onreadystatechange = function(){
if(xhr.readyState === 4){
if(xhr.status >= 200 && xhr.status<300){
result.innerHTML=xhr.response;
}
}
}
})
发送和接收JSON字符串
这里是给/json路由发送的信息,在这里服务端用了一个方法JSON.stringify
把对象转换为字符串,客户端用了一个方法JSON.parse
将字符串转换为对象
<script>
const result = document.querySelector('#result')
window.onkeydown = function(){
const xhr = new XMLHttpRequest();
xhr.open('GET','http://127.0.0.1:8000/json');
xhr.send();
xhr.onreadystatechange = function(){
if(xhr.readyState === 4){
if(xhr.status >= 200 && xhr.status<300){
console.log(xhr.response);
let data = JSON.parse(xhr.response);
result.innerHTML = data.name;
}
}
}
}
</script>
设置超时时间和网络异常情况
/time 路由设置了定时器,3s后返回,我们在客户端设置2s超时时间,故意创造了一个bug
<script>
const btn = document.querySelector('button')
const result = document.querySelector('#result')
btn.onclick = function(){
const xhr = new XMLHttpRequest();
// 超时时间的设置,单位毫秒
xhr.timeout = 2000;
// 超时的回调函数
xhr.ontimeout = function(){
alert('网络异常,请稍后')
}
// 网络异常的回调
xhr.onerror = function(){
alert('网络出问题啦')
}
xhr.open('GET','http://127.0.0.1:8000/time');
xhr.send();
xhr.onreadystatechange = function(){
if(xhr.readyState === 4){
if(xhr.status >= 200 && xhr.status<300){
console.log(xhr.response);
let data = JSON.parse(xhr.response);
result.innerHTML = data.name;
}
}
}
}
</script>
取消发送
取消发送一般是用于重复请求问题,重复的请求过多会对服务器造成压力
<script>
const btn = document.querySelector('button')
let isSending = false;
btn.onclick = function(){
const x = new XMLHttpRequest();
if(isSending){
x.abort // 如果创建一个新的,那也只能最后一个发送
}
isSending = true;
x.open('GET','http://127.0.0.1:8000/time')
x.send();
x.onreadystatechange = function(){
if(x.readyState===4){
isSending = false;
if(xhr.status >= 200 && xhr.status<300){
console.log(xhr.response);
let data = JSON.parse(xhr.response);
result.innerHTML = data.name;
}
}
}
}
</script>
fetch发送
<script>
const btn = document.querySelector('button')
btn.onclick = function(){
fetch('http:127.0.0.1:8000/json',{
method:'POST',
headers:{
id:7,
vip:8,
},
body:JSON.stringify({password:'123'})
}).then(response=>{
return response.json()
}).then(response=>{
console.log(response)
})
}
</script>
五、JQuery-Ajax
JQuery有三种方法发送请求,分别是get方法,post方法和通用方法
<body>
<h2>jquery发送Ajax请求</h2>
<button>GET</button>
<button>POST</button>
<button>通用型方法</button>
<script>
$('button').eq(0).click(function () {
$.get('http:127.0.0.1:8000/json', { a: 100, b: 200 }, function (data) {
// data是回调得到的参数
console.log(data)
})
})
$('button').eq(1).click(function () {
$.post('http:127.0.0.1:8000/json', { a: 100, b: 200 }, function (data) {
data = JSON.parse(data);
console.log(data.name);
})
})
// 通用方法发送请求
$('button').eq(2).click(function () {
$.ajax({
// url
url: 'http:127.0.0.1:8000/json',
//参数
data: { a: 100, b: 200 },
//请求类型
type: 'GET',
// 成功的回调函数
success: function (data) {
data = JSON.parse(data);
console.log(data.name);
},
// 失败的回调
error: function () {
console.log('网络异常')
},
// 超时时间
timeout: 3000,
// 头信息
headers = {
c: 300,
d: 400,
}
})
})
</script>
</body>
六、Axios-Ajax
使用axios需要先引用这个文件
<script src="https://cdn.bootcdn.net/ajax/libs/axios/0.21.1/axios.js"></script>
<body>
<button>GET</button>
<button>POST</button>
<button>AJAX</button>
<script>
const btns = document.querySelectorAll('button');
// 配置baseURL,这样的话后面的链接就会自动和这个地址拼接
axios.defaults.baseURL = 'http://127.0.0.1:8000';
btns[0].onclick = function () {
axios.get('/json', {
// URL参数
params: {ID: 1234,VIP: 7},
headers: {name: 'LYJ'}
}).then(value => {
console.log(value)
})
}
btns[1].onclick = function () {
axios.post('/json',
// 表单参数
{username: 'admin',password: '123'},
// 其他参数
{params: {ID: 1234,VIP: 7},headers: {name: 'LYJ'},}
).then(response=>{
console.log(response.status)
})
}
btns[2].onclick = function () {
axios({
method: 'POST',
url: '/json',
params: {vip: 2,id: 2},
headers: {a: 100,b: 200},
data: {username: 'admin',password: '123'}
}).then(response => {
console.log(response);
console.log(response.status);
console.log(response.statusText);
console.log(response.headers);
console.log(response.data);
})
}
</script>
</body>
七、怎么解决跨域问题
同源策略
如果两个 URL 的 protocol、port (en-US) (如果有指定的话)和 host 都相同的话,则这两个 URL 同源
下表给出了与 URL http://store.company.com/dir/page.html
的源进行对比的示例:
URL | 结果 | 原因 |
---|---|---|
http://store.company.com/dir2/other.html | 同源 | 只有路径不同 |
http://store.company.com/dir/inner/another.html | 同源 | 只有路径不同 |
https://store.company.com/secure.html | 失败 | 协议不同 |
http://store.company.com:81/dir/etc.html | 失败 | 端口不同 ( http:// 默认端口是80) |
http://news.company.com/dir/other.html | 失败 | 主机不同 |
同源策略是一个重要的安全策略,它用于限制一个origin的文档或者它加载的脚本如何能与另一个源的资源进行交互。它能帮助阻隔恶意文档,减少可能被攻击的媒介。
解决跨域问题
我们不可能只访问一个服务器的资源,当我们访问不同的服务器资源时,跨域问题必将显现出来
针对跨域问题我们重新写一个服务端,注意我们这个服务端监听9000端口
const { request, response } = require('express');
const express = require('express');
const app = express();
app.get('/home', (request, response) => {
// 响应一个页面,即发送index.html
response.sendFile(__dirname+'/index.html')
})
app.get('/data', (request, response) => {
response.send('用户数据')
})
app.listen(9000, () => {
console.log('服务已经启动')
})
我们写一个get请求,这个页面命名为index.html
<body>
<button>点击获取服务端数据</button>
<div>ready</div>
<script>
const btn = document.querySelector('button');
const mydiv = document.querySelector('div');
btn.onclick = 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){
mydiv.innerHTML=xhr.response;
}
}
}
}
</script>
</body>
此时是可以请求成功的,但是我们向http://127.0.0.1:8000/server
这个路由发送请求时,发现出现了跨域问题,由于端口号的不一致,我们无法访问。
此时可以使用jsonp
,这个策略是因为一些标签天生具有跨域能力img
,vedio
,script
,iframe
等等,这样的话我们可以把数据放入script
的js数据中进行访问。
这里我们用jquery
$.getJSON('http://127.0.0.1:8000/server?callback=?',function(data){
console.log(data)
})
后端需要接受callback字符串
let cb = request.query.callback
response.end('${cb}($(str))')
CORS解决方案
这是一个官方的解决方案,她的特点是不在客户端操作,全部在服务器完成,通过设置一个响应头来告诉浏览器,该请求允许跨域,浏览器收到该响应以后就会放行,
在我们的node.js服务其中就是设置这个字段,*统配所有字符,这里我们就可以设置可以放行的域
response.setHeader('Access-Control-Allow-Origin', '*');
例如我们设置为
response.setHeader('Access-Control-Allow-Origin', 'http://127.0.0.1:9000/server');
这样我们之前写的那个9000端口的服务就可以访问了
更多地CORS文档https://developer.mozilla.org/zh-CN/docs/Web/HTTP/CORS