本文最后更新于:2021年4月8日 下午
AJAX
简介
AJAX 全称为 Asynchronous JavaScript And XML,就是异步的 JS 和 XML。
通过 AJAX 可以在浏览器中向服务器发送异步请求,最大的优势:无刷新获取数据。
AJAX 不是新的编程语言,而是一种将现有的标准组合在一起使用的新方式。
特点
- 优点
可以无需刷新页面而与服务器端进行通信
允许根据用户事件来更新部分页面内容
- 缺点
没有浏览历史,不能回退
存在跨域问题(同源)
SEO 不友好
HTTP协议
请求报文
1 2 3 4 5 6 7
| 行 POST /s?ie=utf-8 HTTP/1.1 头 Host: atguigu.com Cookie: name=guigu Content-type: application/x-www-form-urlencoded User-Agent: chrome 83 空行 体 username=admin&password=admin
|
在 Chrome 浏览器中,
Headers => Request Headers 查看请求报文行、头
Headers => From Data 查看请求体
响应报文
1 2 3 4 5 6 7 8 9 10 11 12
| 行 HTTP/1.1 200 OK 头 Content-Type: text/html;charset=utf-8 Content-length: 2048 Content-encoding: gzip 空行 体 <html> <head> </head> <body> <h1>XXX</h1> </body> </html>
|
Headers => Response Headers 查看响应行、头
Response 查看响应体
原生方法
GET
1 2 3 4 5 6 7 8 9 10 11 12
| 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("服务已经启动,8000端口监听中......") })
|
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
| <!DOCTYPE html> <html lang="en">
<head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>AJAX GET 请求</title> <style> #result { width: 200px; height: 100px; border: solid 1px red; } </style> </head>
<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') xhr.send() xhr.onreadystatechange = function () { if (xhr.readyState == 4) { if (xhr.status >= 200 && xhr.status < 300) {
result.innerHTML = xhr.response } } } } </script> </body>
</html>
|
- 设置请求参数
直接在url后以?开始加上,如上述代码url参数可改成http://127.0.0.1:8000/server?a=100&b=200&c=300
POST
1 2 3 4 5 6 7 8 9 10 11 12 13
| 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("服务已经启动,8000端口监听中......") })
|
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
| <!DOCTYPE html> <html lang="en">
<head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>AJAX POST 请求</title> <style> #result { width: 200px; height: 100px; border: solid 1px red; } </style> </head>
<body> <div id="result"></div> <script> const result = document.getElementById('result') result.addEventListener('mouseover', function () { const xhr = new XMLHttpRequest() xhr.open('POST', 'http://127.0.0.1:8000/server') xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded') 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>
|
- 设置请求参数
在xhr.send()
里面添加,格式灵活,不限于’a=100&b=200’的样式。
- 设置请求头
在xhr.setRequestHeader()
里设置
若要自定义请求头如xhr.setRequestHeader('name', 'fehek')
,需要在server.js里面添加响应头,新建一个app.all函数(可以接收任意类型的请求),在里面添加response.setHeader('Access-control-Allow-Headers', '*')
JSON响应
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| 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: 'fehek' } let str = JSON.stringify(data) response.send(str) })
app.listen(8000, () => { console.log("服务已经启动,8000端口监听中......") })
|
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 name="viewport" content="width=device-width, initial-scale=1.0"> <title>JSON响应</title> <style> #result { width: 200px; height: 100px; border: solid 1px 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) {
console.log(xhr.response) result.innerHTML = xhr.response.name } } } } </script> </body>
</html>
|
IE缓存问题
IE在实现ajax时,会优先以缓存的结果展现
解决方法:在请求中加一个时间戳,这样每次实际发送的请求都会不一样
如xhr.open('GET', 'http://127.0.0.1:8000/ie?t=' + Date.now())
请求超时
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| const express = require('express') const app = express()
app.get('/delay', (request, response) => { response.setHeader('Access-control-Allow-Origin', '*') setTimeout(() => { response.send('延时响应') }, 3000) })
app.listen(8000, () => { console.log("服务已经启动,8000端口监听中......") })
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| btn.addEventListener('click', 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/delay') xhr.send() xhr.onreadystatechange = function () { if (xhr.readyState == 4) { if (xhr.status >= 200 && xhr.status < 300) { result.innerHTML = xhr.response } } } })
|
取消请求
调用abort
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| <body> <button>点击发送</button> <button>点击取消</button> <script> const btns = document.querySelectorAll('button') let xhr = null
btns[0].onclick = function () { xhr = new XMLHttpRequest() xhr.open('GET', 'http://127.0.0.1:8000/delay') xhr.send() }
btns[1].onclick = function () { xhr.abort() } </script> </body>
|
重复请求
若重复发送相同请求,取消之前的请求,实现最新的请求
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
| <body> <button>点击发送</button> <script> const btn = document.getElementsByTagName('button')[0] 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/delay') xhr.send() xhr.onreadystatechange = function () { if (xhr.readyState == 4) { isSending = false } } } </script> </body>
|
其它方法
JQuery发送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.all('/jQuery-server', (request, response) => { response.setHeader('Access-control-Allow-Origin', '*') response.setHeader('Access-control-Allow-Headers', '*') const data = { name: 'fehek' } response.send(JSON.stringify(data)) })
app.listen(8000, () => { console.log("服务已经启动,8000端口监听中......") })
|
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
| <!DOCTYPE html> <html lang="en">
<head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>jQuery 发送 AJAX 请求</title> <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.5.1/jquery.min.js"></script> </head>
<body> <div class="container"> <h2 class="page-header">jQuery发送AJAX请求</h2> <button>GET</button> <button>POST</button> <button>通用型方法ajax</button> </div> <script> $('button').eq(0).click(function () { $.get('http://127.0.0.1:8000/jQuery-server', { a: 100, b: 200 }, function (data) { console.log(data) }, 'json') }) $('button').eq(1).click(function () { $.post('http://127.0.0.1:8000/jQuery-server', { a: 100, b: 200 }, function (data) { console.log(data) }) }) $('button').eq(2).click(function () { $.ajax({ url: 'http://127.0.0.1:8000/jQuery-server', data: { a: 100, b: 200 }, type: 'GET', dataType: 'json', success: function (data) { console.log(data) }, timeout: 2000, error: function () { console.log('ERROR!') }, headers: { c: 300, d: 400 } }) }) </script> </body>
</html>
|
axios发送AJAX
axios
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| 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: 'fehek' } response.send(JSON.stringify(data)) })
app.listen(8000, () => { console.log("服务已经启动,8000端口监听中......") })
|
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 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94
| <!DOCTYPE html> <html lang="en">
<head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>axios 发送 AJAX 请求</title> <script src="https://cdn.bootcdn.net/ajax/libs/axios/0.21.1/axios.js"></script> </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, level: 5 }, headers: { name: 'fehek', age: 21 } }).then(value => { console.log(value) }) }
btns[1].onclick = function () { axios.post('/axios-server', { username: 'admin', password: 'admin' }, { params: { id: 100, level: 5 }, headers: { height: 170, weight: 170, } }) }
btns[2].onclick = function () { axios({ method: 'POST', url: '/axios-server', params: { id: 100, level: 5 }, headers: { a: 100, b: 200 }, data: { username: 'admin', password: 'admin' } }).then(response => { console.log(response.status) console.log(response.statusText) console.log(response.headers) console.log(response.data) }) } </script> </body>
</html>
|
fetch发送AJAX
fetch
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
| <!DOCTYPE html> <html lang="en">
<head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>fetch 发送 AJAXA 请求</title> </head>
<body> <button>AJAX请求</button> <script> const btn = document.querySelector('button'); btn.onclick = function () { fetch('http://127.0.0.1:8000/fetch-server?id=10', { method: 'POST', headers: { name: 'fehek' }, body: 'username=admin&password=admin' }).then(response => { return response.json() }).then(response => { console.log(response) }) } </script> </body>
</html>
|
跨域
同源:协议、域名、端口号必须完全相同。
违背同源策略就是跨域。
解决方法
JSONP
JSONP(JSON with Padding)是一个非官方的跨域解决方案,只支持 get 请求。
在网页有一些标签天生具有跨域能力,比如:img,link,iframe,script。JSONP 就是利用 script 标签的跨域能力来发送请求的。
- 动态的创建一个 script 标签
var script = document.createElement("script")
- 设置 script 的 src,设置回调函数
1 2 3 4
| script.src = "http://localhost:3000/testAJAX?callback=abc" function abc(data) { alert(data.name) }
|
- 将 script 添加到 body 中
document.body.appendChild(script)
- 服务器中路由的处理
1 2 3 4 5 6 7 8 9
| router.get("/testAJAX", function (req, res) { console.log("收到请求"); var callback = req.query.callback; var obj = { name: "fehek", id: 100 } res.send(callback + "(" + JSON.stringify(obj) + ")"); })
|
CORS
CORS
CORS(Cross-Origin Resource Sharing),跨域资源共享。
CORS 是官方的跨域解决方案,它的特点是不需要在客户端做任何特殊的操作,完全在服务器中进行处理,支持 get 和 post 请求。
1 2 3 4 5
|
res.set("Access-Control-Allow-Origin","*") res.set("Access-Control-Allow-Headers","*") res.set("Access-Control-Allow-Method","*")
|