AJAX
Asynchronous JavaScript And XML,译为 异步的 JS 和 XML
通过AJAX可以在浏览器中向服务器发送异步请求,最大的优势:无刷新获取数据。
XML (可扩展标记语言)
用来存储数据。但其基本被JSON取代
AJAX的特点
优点:
-
可以无需刷新页面而与服务器进行通信。
-
允许根据用户事件来更新部分页面内容。
缺点:
-
没有浏览历史,不能回退
-
存在跨域问题 (同源)
-
SEO不友好
HTTP协议
(hypertext transport protocol)协议 【超文本传输协议】,协议详细规定了浏览器和万维网服务器之间互相通信的规则
请求报文和响应报文
二者格式都是:
行
头
空行
体
按步骤引用express框架
get:
html:
<!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> <body> <button>点击发送请求</button> <div id="res"></div> <script> const btn = document.getElementsByTagName('button')[0]; //绑定事件 btn.onclick = function(){ //1.创建对象 const xhr = new XMLHttpRequest(); //2.初始化 设置请求方法和 url xhr.open('GET','http://localhost:8000/server?a=100&b=200'); //3.发送 xhr.send(); //4.事件绑定 处理服务端返回的结果 // on 当...时候 // readystate 是 xhr 对象中的属性,表示状态 0 1 2 3 4 // change 改变 xhr.onreadystatechange = function(){ //判断(服务端返回了所有的结果) if(xhr.readyState === 4) { //判断响应状态码 200 404 403 401 500 //2xx都是表示成功 if(xhr.status >=200 && xhr.status < 300) { //处理结果 行 头 空行 体 //1.响应行 console.log(xhr.status);//状态码 console.log(xhr.statusText);//状态字符串 console.log(xhr.getAllResponseHeaders());//所有响应头 console.log(xhr.response);//响应体 }else{ } } } } </script> </body> </html>
js:
// 引入express const express = require('express'); //创建应用对象 const app = express(); //创建路由规则 //request 是对请求报文的封装 //response 是对响应报文的封装 app.get('/server', (request, response) => { //设置响应头 设置允许跨域 response.setHeader('Access-Control-Allow-Origin', '*'); //设置响应体 response.send('HELLO AJAX'); }); app.listen(8000, () => { console.log("服务器已经启动,8000 端口监听中...."); });
post:
<!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> #res{ width: 100px; height: 50px; background-color: gray; border-radius: 10px; } </style> </head> <body> <div id="res"></div> <script> //获取元素对象 const res = document.getElementById('res'); //绑定事件 res.onmouseover = function(){ //1.创建对象 const xhr = new XMLHttpRequest(); //2.初始化设置类型与URL xhr.open('POST','http://127.0.0.1:8000/server'); //3.发送 xhr.send(); //4.事件绑定 xhr.onreadystatechange = function(){ //判断 if(xhr.readyState === 4) { //处理服务端返回的结果 res.innerHTML = xhr.response; } } } </script> </body> </html>
// 引入express const express = require('express'); //创建应用对象 const app = express(); //创建路由规则 //request 是对请求报文的封装 //response 是对响应报文的封装 app.get('/server', (request, response) => { //设置响应头 设置允许跨域 response.setHeader('Access-Control-Allow-Origin', '*'); //设置响应体 response.send('HELLO AJAX'); }); app.post('/server', (request, response) => { //设置响应头 设置允许跨域 response.setHeader('Access-Control-Allow-Origin', '*'); //设置响应体 response.send('HELLO AJAX POST'); }); app.listen(8000, () => { console.log("服务器已经启动,8000 端口监听中...."); });
设置请求体
请求体在send()方法中设置
xhr.send('a=100&b=200&c=300');
设置请求头信息
setRequestHeader()
在open和send方法中间设置请求头
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');
服务端响应json数据
接收服务端的数据只能接收字符串
所以当服务端要传字符串时,需要将对象进行字符串转化
let str = JSON.stringify(data);
js:
// 引入express const express = require('express'); //创建应用对象 const app = express(); app.all('/json-server', (request, response) => { //设置响应头 设置允许跨域 response.setHeader('Access-Control-Allow-Origin', '*'); //响应一个数据 const data = { name:'xiaotao' } //对对象进行字符串转换 let str = JSON.stringify(data); // 设置响应体 response.send(str); }); app.listen(8000, () => { console.log("服务器已经启动,8000 端口监听中...."); });
接收服务端数据后将数据转换为对象
两种方式:
-
手动对数据进行转化
let data = JSON.parse(xhr.response); console.log(data);
-
自动转换
//设置响应体数据类型 xhr.responseType = 'json';
console.log(xhr.response); res.innerHTML = xhr.response.name;
整体代码:
<script> const res = document.getElementById('res'); // 绑定键盘按下事件 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) { // 手动对数据转化 // let data = JSON.parse(xhr.response); // console.log(data); //自动转换 console.log(xhr.response); res.innerHTML = xhr.response.name; } } } } </script>
请求超时和网络异常处理
ontimeout():请求超时事件
onerror():无网络事件
//超时设置 xhr.timeout = 2000; //超时回调 xhr.ontimeout = function(){ alert("网络异常,请稍后重试"); } xhr.onerror = function(){ alert("你的网络似乎出了一些问题"); }
完整script代码:
<script> const btn = document.getElementsByTagName('button') [0]; const res = document.querySelector('#res'); 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) { res.innerHTML = xhr.response; } } } }); </script>
取消请求
当请求还没有到达的时候取消请求,使用abort方法
x.abort();
完整代码:
<!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> <body> <button>点击发送</button> <button>点击取消</button> <script> const btns = document.getElementsByTagName('button'); let x = null; btns[0].onclick = function(){ x = new XMLHttpRequest(); x.open('GET','http://127.0.0.1:8000/delay'); x.send(); } btns[1].onclick = function(){ x.abort(); } </script> </body> </html>
// 引入express const { response } = require('express'); const express = require('express'); //创建应用对象 const app = express(); //延时响应 app.get('/delay', (request, response) => { response.setHeader('Access-Control-Allow-Origin', '*') setTimeout(() => { response.send('延时响应'); }, 2000); }); //监听端口启动服务 app.listen(8000, () => { console.log("服务器已经启动,8000 端口监听中...."); });
重复请求发送问题
为了提升效率,避免用户重复发送相同的请求,当用户按下请求时,判断是否已有请求,如果有,取消上一个请求,创建一个新的请求。
const btns = document.getElementsByTagName('button'); let x = null; //标识变量 let isSending = false; btns[0].onclick = function(){ //判断标识变量 if(isSending) { x.abort();//如果正在发送,则取消请求,创建一个新的请求 } x = new XMLHttpRequest(); //需修改标识变量的值 isSending = true; x.open('GET','http://127.0.0.1:8000/delay'); x.send(); x.onreadystatechange = function(){ if(x.readyState === 4) { //修改标识变量 isSending = false; } } }
同源策略
是浏览器的一种安全策略
同源:协议、域名、端口号 必须完全相同
违背同源策略就是跨域
跨域的解决方案
-
JSONP
JSONP是一个非官方的跨域解决方案,纯粹凭借程序员的聪明才智开发出来,只支持get请求
JSONP是借助script来实现跨域的
原生JSONP案例:
<!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> 用户名:<input type="text" id="username"> <p></p> <script> const input = document.querySelector('input'); const p = document.querySelector('p'); //声明handle函数 function handle(data){ input.style.border = "solid 1px #f00"; //修改p标签的提示文本 p.innerHTML = data.msg; } //绑定事件 input.onblur = function(){ //获取用户输入的值 let username = this.value; //向服务器端发送请求,检测用户名是否存在 //1.创建一个script标签 const script = document.creatElement('script'); //2.设置标签的 src 属性 script.src = 'http://127.0.0.1:8000/check-username' //3.将script插入到文档中 document.body.appendChild(script); } </script> </body> </html>
CORS
跨域资源共享,是官方的解决跨域的方法
一般来说是设置响应头:
response.setHeader('Access-Control-Allow-Origin', '*');