简介
- AJAX 全称为 Asynchronous JavaScript And XML,就是异步的 JS 和 XML(现在已经基本被json取代)。
- 通过 AJAX 可以在浏览器中向服务器发送异步请求,最大的优势:无刷新获取数据。
- AJAX 不是新的编程语言,而是一种将现有的标准组合在一起使用的新方式。
优点
- 无需刷新页面即可与服务器进行通信。
- 允许根据用户事件来更新部分页面内容。
缺点
- 没有浏览历史,不能回退
- 存在跨域问题,ajax默认是遵循同源策略,跨域请求是无法通过ajax请求的
- seo不友好,无法通过爬虫获取到ajax请求的数据,也无法在浏览器的源代码选项中获取到相关的源码
总而言之:ajax不是什么新鲜的对象,我们把它当作是在一个已有的网页中,我们可以通过它请求后端的数据来显示在之前的网页中。
AJAX的使用
- GET请求
btn.onclick = function(){ //1. 创建对象 const xhr = new XMLHttpRequest();//浏览器开发者选项中的xhr里面的信息就是该页面的ajax请求 //2. 初始化 设置请求方法和 url xhr.open('GET', 'http://127.0.0.1:8000/server?a=100&b=200&c=300'); //3. 发送 xhr.send(); //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());//所有响应头 // console.log(xhr.response);//响应体 //设置 result 的文本 result.innerHTML = xhr.response; }else{ } } } }
- POST请求
result.addEventListener("mouseover", function(){ //1. 创建对象 const xhr = new XMLHttpRequest(); xhr.responseType='json' //2. 初始化 设置类型与 URL xhr.open('POST', 'http://127.0.0.1:8000/server');//有时候ie浏览器会有缓存问题,因此通常情况下最好给每个url拼接上一个时间戳参数 //设置请求头 xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded'); xhr.setRequestHeader('name','xxx');//自定义的请求头需要在后端中设置Access-Control-Allow-Headers响应头 //3. 发送 xhr.send('a=100&b=200&c=300'); // xhr.send('a:100&b:200&c:300'); // xhr.send('1233211234567'); //4. 事件绑定 xhr.onreadystatechange = function(){ //判断 if(xhr.readyState === 4){ if(xhr.status >= 200 && xhr.status < 300){ //处理服务端返回的结果 result.innerHTML = xhr.response; } } } });
- 超时与网络异常问题
btn.addEventListener('click', function(){ const xhr = new XMLHttpRequest(); //超时设置 2s 设置 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; } } } })
- 重复请求问题——关键在于设置一个标志位
<script> //获取元素对象 const btns = document.querySelectorAll('button'); let x = null; //标识变量 let isSending = false; // 是否正在发送AJAX请求 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; } } } // abort btns[1].onclick = function(){ x.abort(); } </script>
- 使用express框架搭建一个后端
//1. 引入expressconst express = require('express');//2. 创建应用对象const app = express();//3. 创建路由规则// request 是对请求报文的封装// response 是对响应报文的封装//all方法表示所有类型的请求都可以,get、post、delete。。。app.all('/server', (request, response)=>{ //设置响应 //response.set("Access-Control-Allow-Origin","http://127.0.0.1:3000");//只对http://127.0.0.1:3000这个url的请求允许跨域 response.setHeader("Access-Control-Allow-Origin","*")//对所有请求允许跨域 response.setHeader("Access-Control-Allow-Headers","*")//允许各种请求头,包括自定义的和http已经定义的请求头 response.send('HELLO EXPRESS');});//4. 监听端口启动服务app.listen(8000, ()=>{ console.log("服务已经启动, 8000 端口监听中....");});
AJAX的请求状态
xhr.readyState 可以用来查看请求当前的状态
- 0: 表示 XMLHttpRequest 实例已经生成,但是 open()方法还没有被调用。
- 1: 表示 send()方法还没有被调用,仍然可以使用 setRequestHeader(),设定 HTTP请求的头信息。
- 2: 表示send()方法已经执行,并且头信息和状态码已经收到。
- 3: 表示正在接收服务器传来的body部分的数据。
- 4: 表示服务器数据已经完全接收,或者本次接收已经失败了
跨域问题
同源策略
同源策略是浏览器的一种安全策略。所谓的同源是指:协议、域名】端口号必须完全相同,而违背同源策略就是跨域。
如果违背同源策略,浏览器的开发者工具就会报如下错误,该网页是从5500端口获取的,但是ajax的请求却是8000端口。
解决跨域问题有两种方式:CORS
- CORS(Cross-Origin Resource Sharing),跨域资源共享。CORS 是官方的跨域解决方案,它的特点是不需要在客户端做任何特殊的操作,完全在服务器中进行处理,支持get 和 post 请求。跨域资源共享标准新增了一组 HTTP 首部字段,允许服务器声明哪些源站通过浏览器有权限访问哪些资源
- CORS 怎么工作的?
CORS 是通过设置一个响应头来告诉浏览器,该请求允许跨域,浏览器收到该响应以后就会对响应放行。
JSONP
JSONP(JSON with Padding),是一个非官方的跨域解决方案,只支持 get 请求。在网页有一些标签天生具有跨域能力,比如:img link iframe script。JSONP 就是利用 script 标签的跨域能力来发送请求的。案例如下:
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>案例</title></head><body> 用户名: <input type="text" id="username"> <p></p> <script> //获取 input 元素 const input = document.querySelector('input'); const p = document.querySelector('p'); //声明 handle 函数 function handle(data){ input.style.border = "solid 1px #f00"; //修改 p 标签的提示文本 console.log(data) p.innerHTML = data.name; } //绑定事件 input.onblur = function(){ //获取用户的输入值 let username = this.value; //向服务器端发送请求 检测用户名是否存在 //1. 创建 script 标签 const script = document.createElement('script'); //2. 设置标签的 src 属性 script.src = 'http://127.0.0.1:8000/server'; //3. 将 script 插入到文档中 document.body.appendChild(script); } </script></body></html>
//1. 引入expressconst express = require('express');//2. 创建应用对象const app = express();//3. 创建路由规则// request 是对请求报文的封装// response 是对响应报文的封装app.all('/server', (request, response)=>{ //设置响应 // response.setHeader("Access-Control-Allow-Origin","*") // response.setHeader("Access-Control-Allow-Headers","*") const data = { name: 'sdsdsd' }; response.end(`handle(${JSON.stringify(data)})`);//这样就会回调到html中的handle方法});//4. 监听端口启动服务app.listen(8000, ()=>{ console.log("服务已经启动, 8000 端口监听中....");});
最后
除了前面介绍的几个字ajax的请求之外,fetch函数也是可以用来进行ajax请求的
https://developer.mozilla.org/zh-CN/docs/Web/API/fetch