Ajax
简介
Ajax:异步JavaScript和XML,通过Ajax可以在浏览器中向服务器发送异步请求,最大的优势就是:无刷新获取数据;他不是一门新的编程语言,而是将现有的标准组合在一起使用的新方式。
XML:可扩展标记语言,用于传输和存储数据。
XML和HTML类似,不同的是HTML都是预定义格式,全都是自定义标签,用来表示一些数据。
JSON:相对XML更加简洁,更加灵活,格式转化方便。
- Ajax的优点:
- 可以无需刷新页面与服务器端进行通信
- 允许根据用户事件更新部分页面内容
- Ajax缺点:
- 没有浏览历史,不能回退
- 存在跨域问题
- SEO不友好(搜索引擎优化,爬虫爬不到)
发送GET请求
网页
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
| <!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>Ajax Get请求</title> </head> <style> #result { width: 200px; height: 100px; border: 1px red solid; } </style>
<body> <button> 点击发送请求 </button> <div id="result"></div> <script> const btn = document.getElementsByTagName('button')[0]; const result = document.getElementById('result'); btn.onclick = function () { const xhr = new XMLHttpRequest(); xhr.open('GET', 'http://127.0.0.1:8000/server?a=100&b=200&c=300'); xhr.send(); xhr.onreadystatechange = function () { /* readystate是xhr对象中的属性值,表示状态,0/1/2/3/4 0:未初始化 1:表示open方法调用完毕 2:send方法调用完毕 3:服务端返回了部分结果 4:服务端返回了所有结果 */ if (xhr.readyState === 4) { if (xhr.status >= 200 && xhr.status < 300) { console.log(xhr.status); console.log(xhr.responseText); console.log(xhr.getAllResponseHeaders()); console.log(xhr.response);
result.innerHTML = xhr.response; } else {
} } }
} </script> </body>
</html>
|
后端
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| const express = require('express')
const app = express()
app.get('/server', (request, response) => { response.setHeader('Access-Control-Allow-Origin', '*')
response.send('Hello Ajax') })
app.listen(8000, () => { console.log('服务已启动') })
|
cmd启动
发送POST请求
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| <!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>Ajax Post请求</title> <style> #result { width: 100px; height: 200px; border: 1px solid red; } </style> </head>
<body> <div id="result"></div> <script> const result = document.getElementById("result"); result.addEventListener("mouseover", function () { xhr = new XMLHttpRequest(); xhr.open('POST', 'http://127.0.0.1:8000/server'); xhr.send(); xhr.onreadystatechange = function () { if (xhr.readyState === 4) { if (xhr.status >= 200 && xhr.status < 300) { result.innerHTML = xhr.response; } } } })
</script> </body>
</html>
|
服务端
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| const express = require('express')
const app = express()
app.post('/server', (request, response) => { response.setHeader('Access-Control-Allow-Origin', '*')
response.send('Hello Ajax POST') })
app.listen(8000, () => { console.log('服务已启动') })
|
cmd启动
设置头部行信息
一般会把身份校验信息放在头部行中。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| <!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>Ajax Post请求</title> <style> #result { width: 100px; height: 200px; border: 1px solid red; } </style> </head>
<body> <div id="result"></div> <script> const result = document.getElementById("result"); result.addEventListener("mouseover", function () { xhr = new XMLHttpRequest(); xhr.open('POST', 'http://127.0.0.1:8000/server'); xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); xhr.setRequestHeader('name', 'zhangjialin'); xhr.send('a=100:b=200:c=300'); xhr.onreadystatechange = function () { if (xhr.readyState === 4) { if (xhr.status >= 200 && xhr.status < 300) { result.innerHTML = xhr.response; } } } })
</script> </body>
</html>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| const express = require('express')
const app = express()
app.all('/server', (request, response) => { response.setHeader('Access-Control-Allow-Origin', '*') response.setHeader('Access-Control-Allow-Headers', '*') response.send('Hello Ajax POST') })
app.listen(8000, () => { console.log('服务已启动') })
|
服务端响应JSON数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| <!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>Json响应</title> <style> #result { width: 100px; height: 200px; border: 1px solid red; } </style> </head>
<body> <div id="result"></div> <script> const result = document.getElementById("result"); window.onkeydown = 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) { result.innerHTML = xhr.response.name;
} } } } </script> </body>
</html>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| const express = require('express')
const app = express()
app.all('/json-server', (request, response) => { response.setHeader('Access-Control-Allow-Origin', '*') response.setHeader('Access-Control-Allow-Headers', '*') const data = { name: '张加林', age: 20, gender: 'male', } let str = JSON.stringify(data) response.send(str) })
app.listen(8000, () => { console.log('服务已启动') })
|
nodemon自动重启工具
1
| nodemon .\express基本使用.js
|
Ajax-IE缓存问题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| <!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>IE缓存</title> <style> #result { width: 100px; height: 200px; border: 1px solid red; } </style> </head>
<body> <button id='btn'>点击发送请求</button> <div id="result"></div> <script> const btn = document.getElementById("btn"); const result = document.querySelector('#result') btn.addEventListener("click", function () { const xhr = new XMLHttpRequest(); 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>
</html>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| const express = require('express')
const app = express()
app.all('/server', (request, response) => { response.setHeader('Access-Control-Allow-Origin', '*') response.setHeader('Access-Control-Allow-Headers', '*') const data = { name: 'ycy', age: 20, gender: 'male', } let str = JSON.stringify(data) response.send(str) })
app.get('/ie', (request, response) => { response.setHeader('Access-Control-Allow-Origin', '*') response.send('Hello IE-12') })
app.listen(8000, () => { console.log('服务已启动') })
|
Ajax请求超时与网络异常处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
| <!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>请求超时与网络异常处理</title> <style> #result { width: 100px; height: 200px; border: 1px solid red; } </style> </head>
<body> <button id="btn">请求</button> <div id="result"></div> <script> const btn = document.getElementById("btn"); const result = document.querySelector('#result') btn.addEventListener("click", function () { const xhr = new XMLHttpRequest(); xhr.timeout = 2000; xhr.ontimeout = function () { result.innerHTML = '超时!!!'; } xhr.onerror = function () { result.innerHTML = '网络异常'; }
xhr.open('GET', 'http://127.0.0.1:8000/delay'); xhr.send(); xhr.onreadystatechange = function () { if (xhr.readyState === 4) { if (xhr.status >= 200 && xhr.status < 300) { result.innerHTML = xhr.response; } } } } )
</script> </body>
</html>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| const express = require('express')
const app = express()
app.get('/delay', (request, response) => { response.setHeader('Access-Control-Allow-Origin', '*') setTimeout(() => { response.send('Hello IE-12') }, 3000) })
app.listen(8000, () => { console.log('服务已启动') })
|
Ajax取消请求
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| <!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>取消请求</title> </head>
<body> <button>点击发送</button> <button>点击取消</button> <script> let xhr = null; const btns = document.querySelectorAll('button'); btns[0].onclick = function () { xhr = new XMLHttpRequest(); xhr.open('GET', 'http://127.0.0.1:8000/delay'); xhr.send(); xhr.onreadystatechange = function () { if (xhr.readyState === 4) { if (xhr.status >= 200 && xhr.status < 300) {
} } } }
btns[1].onclick = function () { xhr.abort(); } </script> </body>
</html>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| const express = require('express')
const app = express()
app.get('/delay', (request, response) => { response.setHeader('Access-Control-Allow-Origin', '*') setTimeout(() => { response.send('Hello IE-12') }, 3000) })
app.listen(8000, () => { console.log('服务已启动') })
|
Ajax请求重复发送问题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| <!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>Ajax请求重复发送问题</title> </head>
<body> <button>点击发送</button> <script> let xhr = null; let isSending = false;
const btns = document.querySelectorAll('button'); btns[0].onclick = function () { if (isSending) { xhr.abort(); } xhr = new XMLHttpRequest(); isSending = true; xhr.open('GET', 'http://127.0.0.1:8000/delay'); xhr.send(); xhr.onreadystatechange = function () { if (xhr.readyState === 4) { isSending = false; } } } </script> </body>
</html>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| const express = require('express')
const app = express()
app.get('/delay', (request, response) => { response.setHeader('Access-Control-Allow-Origin', '*') setTimeout(() => { response.send('Hello IE-12') }, 3000) })
app.listen(8000, () => { console.log('服务已启动') })
|
JQuery发送Ajax请求
通用方法发送
Axios发送Ajax请求
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
| <!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"> <script crossorigin="anonymous" src="https://cdn.bootcdn.net/ajax/libs/axios/0.21.1/axios.min.js"></script> <title>Axios发送Ajax请求</title> </head>
<body> <button>GET</button> <button>POST</button> <button>AJAX</button> <script> const btns = document.querySelectorAll('button');
axios.defaults.baseURL = 'http://127.0.0.1:8000' btns[0].onclick = function () { axios.get('/axios-server', { params: { id: 100, vip: 7 }, headers: { name: 'ycy' } }).then(value => { console.log(value); }); }
btns[1].onclick = function () { axios.post('/axios-server', { username: 'admin', password: '123456' }, { params: { vip: 100, id: 9 }, headers: { gender: 'man', age: 99 },
}).then(value => { console.log(value); }) } </script> </body>
</html>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| const express = require('express')
const app = express()
app.all('/axios-server', (request, response) => { response.setHeader('Access-Control-Allow-Origin', '*') response.setHeader('Access-Control-Allow-Headers', '*') const data = { name: '张加林' } response.send(JSON.stringify(data)) })
app.listen(8000, () => { console.log('服务已启动') })
|
axios函数发送Ajax请求
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| btns[2].onclick = function () { axios({ method: 'POST', url: '/axios-server', params: { vip: 100, level: 30 }, headers: { a: 100, b: 200 }, 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) }) }
|
使用fetch函数发送Ajax请求
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| <!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>fetch发送Ajax请求</title> </head>
<body> <button>Ajax请求</button> <script> const btn = document.querySelector('button'); btn.onclick = function () { fetch('http://127.0.0.1:8000/fetch-server?vip=100', { method: 'POST', headers: { name: 'zhul' }, body: 'username=admin&password=admin' }).then(response => { return response.json(); }).then(response => { console.log(response); }) } </script> </body>
</html>
|
1 2 3 4 5 6 7
| app.all('/fetch-server', (request, response) => { response.setHeader('Access-Control-Allow-Origin', '*') response.setHeader('Access-Control-Allow-Headers', '*') const data = { name: '张加林' } response.send(JSON.stringify(data)) })
|
跨域问题
同源:协议、域名、端口号必须完全相同。
违背同源策略就是跨域。
Ajax发送请求默认遵循同源策略。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| const express = require('express')
const app = express()
app.get('/home', (req, res) => { res.sendFile(__dirname + '/index.html') })
app.get('/data', (req, res) => { res.send('用户数据') })
app.listen(9000, () => { console.log('服务已经启动……') })
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| <!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>首页</title> </head>
<body> <h1>张加林</h1> <button>获取用户信息</button> <script> const btn = document.querySelector('button'); btn.onclick = function () { const xhr = new XMLHttpRequest(); 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> </body>
</html>
|
通过127.0.0.1:9000/home访问页面后,点击按钮可获得数据;但是直接打开网页访问就会跨域。
JSONP
JSONP:非官方的跨域解决方案,纯粹凭借程序员的聪明才智开发,只支持GET请求。
在网页中有一些标签天生具有跨域能力,比如:img/link/iframe/script
JSONP利用script标签跨域能力来发送请求
JSONP使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| <!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>jsonp原理</title> </head>
<body> <div id="result"></div> <script> function handle(data) { const result = document.getElementById("result"); result.innerHTML = data.name; } </script> <script src='http://127.0.0.1:8000/jsonp-server'></script> </body>
</html>
|
1 2 3 4 5 6 7 8 9
| app.all('/jsonp-server', (request, response) => { const data = { name: '张加林' } let str = JSON.stringify(data) response.end(`handle(${str})`) })
|
原生JSONP实践
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| <!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>原生JSONP实践</title> </head>
<body> <label>用户名:</label> <input type="text" id="t1"> <p></p> <script> let t1 = document.getElementById("t1"); let p = document.querySelector('p');
function handle(data) { t1.style.border = "solid 1px #8080ff"; p.innerHTML = data.msg; }
t1.onblur = function () { let username = this.value; const script = document.createElement('script'); script.src = 'http://127.0.0.1:8000/check-username'; document.body.appendChild(script); } </script> </body>
</html>
|
1 2 3 4 5 6 7 8 9 10
| app.all('/check-username', (request, response) => { const data = { exist: 1, msg: '用户已经存在', } let str = JSON.stringify(data) response.end(`handle(${str})`) })
|
JQuery发送JSONP练习
设置CORS响应头实现跨域
CORS:Cross-Origin-Resource-Sharing,跨域资源共享,是官方的跨域问题解决方案,特点是不需要客户端做任何特殊操作,完全在服务端进行处理,支持post和get请求。跨域对象新增了一组HTTP首部字段,允许服务器声明哪些源通过浏览器有权限访问哪些资源。
工作原理:CORS是通过设置一个响应头来告诉浏览器,该请求允许跨域,浏览器收到该响应以后就会对响应放行。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| app.all('/cors', (request, response) => { response.setHeader('Access-Control-Allow-Origin', '*') response.setHeader('Access-Control-Allow-Headers', '*') response.setHeader('Access-Control-Allow-Methods', '*') const data = { exist: 1, msg: '用户已经存在', } let str = JSON.stringify(data) response.end(`handle(${str})`) })
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| <!DOCTYPE html> <html lang="en">
<head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=\, initial-scale=1.0"> <title>CORS</title> </head>
<body> <button>发送请求</button> <div id="result"></div> <script> const btn = document.querySelector('button'); btn.onclick = function () { let xhr = new XMLHttpRequest(); xhr.open('GET', 'http://127.0.0.1:8000/cors'); xhr.send(); xhr.onreadystatechange = function () { if (xhr.readyState === 4) { if (xhr.status >= 200 && xhr.status < 300) { console.log(xhr.response); } } } } </script> </body>
</html>
|
测试