总结
- 1.创建XMLHttpRequest的实例对象
let xhr = new XMLHttpRequest();
- 2.打开与服务器之间的通道
xhr.open(method, url,async);
其中:
method:请求方式
url:服务端的请求路径
async:是否异步请求(true:异步;false:同步)第三个参数可以省略 默认是true 异步
- 3.发送请求
xhr.send()
注意:get请求不传参数,只有post请求需要传递实体数据
- 4.监听服务器的请求状态
利用事件onreadystatechange完成回调
输出响应体数据结果
接收服务端响应到客户端的结果数据,可以有两种方式:response、responseText
如果服务端响应的数据为基本类型,那么使用response或者是responseText均可
如果服务端响应的数据为JSON对象的话,
方法1. 使用response获取对象数据,但是有一个前提需要设置响应数据类型为jsonxhr.responseType = 'json';
方法2. 使用responseText获取对象数据,那么无需设置响应数据类型,则需要手动通过JSON.parse方法将得到的JSON字符串转换成JSON对象JSON.parse(xhr.responseText)
//xhr.readyState 不同位置的状态
let xhr = new XMLHttpRequest();
console.log(xhr.readyState); //0
xhr.open('get', 'http://127.0.0.1:8080/users/time?title="标题1"&content="内容一"&time=' + Date.now())
console.log(xhr.readyState)//1
xhr.send();
console.log(xhr.readyState);//1 发送后需要时间请求所以是1
xhr.onreadystatechange = () => {
console.log(xhr.readyState);//2 3 4
if (xhr.readyState === 4) {
if (xhr.status >= 200 && xhr.status <= 300) {
console.log(xhr.responseText)
}
}
}
xhr.onreadystatechange = function (){
//根据xhr对象的状态来进行判断
//readyState:是xhr对象中的一个属性,属性值为0,1,2,3,4
//0:表示xhr对象的建立初始化(实例化之后,open之前)
//1:表示调用了open,完成了打开请求(open之后,send之前)
//2:表示调用了send,完成了发送请求(send方法已经调用,但是当前的状态以及http头未知)
//3:表示正在返回数据中
//4:所有的数据完全响应完毕
if(xhr.readyState: == 4){
//status:xhr中的一个属性,表示响应状态码
if(xhr.status == 200){
console.log(xhr.response);//表示响应体的结果
console.log(xhr.responseText);//表示响应体的结果
console.log(xhr.status); //输出响应状态码
console.log(xhr.statusText); //响应状态字符串
console.log(xhr.getAllResponseHeaders());//获取所有响应头
//得到某一个响应头信息
console.log(xhr.getResponseHeader('Content-Type'))
console.log(xhr.getResponseHeader('content-length'))
}
}
}
-
post请求需要设置请求头
XMLHttpRequest.setRequestHeader(header,value)
设置 HTTP 请求头的值。必须在 open() 之后、send() 之前调用 setRequestHeader() 方法
header: 规定头的名称
value: 规定头的值
目前接触到的常见头:
Content-Type:text/html;charset=utf-8
=> 传送的内容既可以是普通文本,也可以是带标签的文本(可以理解为类似于JS中的innerHTML)
Content-Type:text/plain;charset=utf-8
=> 传送的内容为普通文本(可以理解为类似于JS中的innerText)
Content-Type:application/json;charset=utf-8
=> 传送的数据格式为json对象 {键名:键值,键名:键值}
Content-Type:application/x-www-form-urlencoded;charset=utf-8
=> post请求字符串格式:参数名=值&参数名=值
//post请求头为form设置请求头:(用来模拟form表单提交)
xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded")
xhr.timeout = 2000; //2秒钟之内需要有响应,如果没有响应则执行超时函数
xhr.ontimeout = function () {
alert('不好意思,请求超时了,请等待重试!!');
}
xhr.abort();//取消请求
跨域设置
app.get('/server',(request,response)=>{
//允许来自于不同的主机来向我发送跨域请求,必须设置
response.setHeader('Access-Control-Allow-Origin','*');
//允许在请求过程中客户端添加自定义请求头,如果不添加只能使用http中默认的一些请求头
//例如:想要添加a:100就不行,所以这句话需要设置上
response.setHeader('Access-Control-Allow-Headers','*');
//允许所有的请求方法
response.setHeader('Access-Control-Allow-Methods','*');
//设置响应体
response.end('server');
});
ajax在IE中的缓冲问题以及解决方法
在IE浏览器中只要成功的请求响应过结果一次,就会将结果缓存在浏览器中,即使服务端响应的结果更新了;
客户端请求到的数据仍然是上一次的结果,解决办法只需要每一次发送请求时添加时间戳。
xhr.open('get', 'http://127.0.0.1/server?time=' + Date.now());
设置CORS跨域
app.get('/server',(request,response)=>{
//允许来自于不同的主机来向我发送跨域请求,必须设置
response.setHeader('Access-Control-Allow-Origin','*');
//允许在请求过程中添加自定义请求头,如果不添加只能使用http中默认的一些请求头
//例如:想要添加a:100就不行,所以这句话需要设置上
response.setHeader('Access-Control-Allow-Headers','*');
//设置响应体
response.end('server');
});
ajax同步的方法
let xhr = new XMLHttpRequest();
xhr.open('get', 'http://127.0.0.1:8080/users/time?title="标题1"&content="内容一"&time=',false)
xhr.send();
console.log(xhr.responseText)
AJAX
一、什么是ajax 阿贾克斯
ajax全称为Asynchronous javascript and xml,就是异步的js和xml;
目的是通过ajax可以在浏览器中向服务器发送异步请求
,而最大的优势就是可以整体页面无刷新的获取数据
;
ajax不是新的编程语言,而是一种将现有的标准组合在一起使用的新方式(JS中的一种API + 发送的http请求)。
例如:百度关键词搜索、用户名的唯一性验证、新闻的异步加载
二、什么是XML
XML是一种可扩展标记语言
,用来被设计传输和存储数据;
和HTML类似,不同的是,HTML都是预定义标签,XML中全都是自定义标签来表示一些数据。
例如:
有一组学生的数据:
var name = "孙悟空";
var age = 18;
var gender = "男";
用XML表示:
<student>
<name>孙悟空</name>
<age>18</age>
<sex>男</sex>
</student>
<student>
<name>猪八戒</name>
<age>20</age>
<sex>男</sex>
</student>
<stu>
<xingming a="1">张三</xingming>
</stu>
当然,现在已经被JSON格式所取代了。
{"name":"孙悟空","age":18,"gender":"男"}
三、使用原生的AJAX
核心对象:XMLHttpRequest,AJAX的所有操作都是通过该对象进行的。
3.1 使用步骤
- 创建XMLHttpRequest的实例对象
var xhr = new XMLHttpRequest();
- 设置请求信息
xhr.open(method, url);
其中:
method:请求方式
url:服务端的请求路径
- 发送请求
xhr.send()
注意:get请求不传参数,只有post请求需要传递实体数据
-
接收响应
利用事件onreadystatechange完成回调
xhr.onreadystatechange = function (){
//根据xhr对象的状态来进行判断
//readyState:是xhr对象中的一个属性,属性值为0,1,2,3,4
//0:表示xhr对象的建立初始化
//1:表示调用了open,完成了打开请求
//2:表示调用了send,完成了发送请求
//3:表示正在返回数据中
//4:所有的数据完全响应完毕
if(xhr.readyState: == 4){
//status:xhr中的一个属性,表示响应状态码
if(xhr.status == 200){
console.log(xhr.responseText);//表示响应体的结果
console.log(xhr.status); //输出响应状态码
console.log(xhr.statusText); //响应状态字符串
console.log(xhr.getAllResponseHeaders());//获取响应头
}
}
}
3.2 ajax的初体验
案例:点击按钮发送ajax请求
<body>
<button>点击发送一个ajax的get请求</button>
<script>
//1.获取DOM元素对象
let btn = document.querySelector('button');
//2.设置事件回调
btn.onclick = ()=>{
//3.创建ajax对象
let xhr = new XMLHttpRequest();
//4.打开请求
xhr.open('get','http://127.0.0.1/server');
//5.发送请求
xhr.send();
//6.客户端接收服务端的响应
xhr.onreadystatechange = function(){
if(xhr.readyState == 4){
if(xhr.status == 200){
console.log(xhr.responseText);
}
}
}
}
</script>
</body>
//1.引入express
const express = require('express');
//2.创建express对象
const app = express();
//3.设置请求url
app.get('/server',(request,response)=>{
//允许来自于不同的主机来向我发送跨域请求,必须设置
response.setHeader('Access-Control-Allow-Origin','*');
response.send('hello ajax');
})
//4.监听端口并启动服务
app.listen(80,()=>{
console.log('80端口已经启动');
})
3.3 ajax的GET传参问题
- 在请求的url中传递参数
http://127.0.0.1/server?vip=1&keyword=abc&price=2000
- 引入fs模块
const fs = require('fs');
- 添加express的全局中间件
app.use(function(request,response,next){
fs.writeFileSync('./access.log',request.url + "\r\n");
next();
});
案例:仿留言板发送请求数据
<body>
<p>昵称:<input type="text" id="user" /></p>
<p>信息:<textarea cols="30" rows="10" id="content"></textarea></p>
<p><button id="sendBtn">发送</button></p>
<script>
//1、获取元素对象
let sendBtn = document.querySelector('#sendBtn');
//2、绑定事件
sendBtn.addEventListener('click', () => {
//3、获取表单信息
let nickName = document.querySelector('#user').value;
let content = document.querySelector('#content').value;
//4、ajax发送请求
let xhr = new XMLHttpRequest();
xhr.open('get', `http://127.0.0.1/server?nickName=${nickName}&content=${content}`);
xhr.send();
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
console.log(xhr.responseText);
}
}
}
});
</script>
</body>
//引入express
const express = require('express');
//创建服务对象
const app = express();
//引入fs文件系统模块
const fs = require('fs');
//添加express的全局中间件
app.use((request,response,next)=>{
//创建文件保存客户端传递的请求参数数据
//服务端接收客户端传递的请求参数数据
console.log(request.url);
fs.writeFileSync('./data.log', decodeURI(request.url) + '\r\n',{flag:'a'});
next();
});
//创建路由规则
app.get('/server',(request,response)=>{
response.setHeader('Access-Control-Allow-Origin','*');
response.setHeader('Access-Control-Allow-Headers','*');
response.send('ajax请求');
});
//监听端口
app.listen(80,()=>{
console.log('80端口正在启动中...ing');
});
3.4 ajax请求头与请求体的设置
如何发送post请求
<style>
div {
width: 300px;
height: 300px;
border: 1px solid red;
}
</style>
<body>
<div></div>
<script>
//1、获取元素
let div = document.querySelector('div');
//2、绑定事件
div.onclick = function () {
//3、创建ajax对象
const xhr = new XMLHttpRequest();
xhr.open('post', 'http://127.0.0.1/server');
//4、设置请求头
xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
//5、设置请求体数据
xhr.send('vip=9&wd=abc');
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if (xhr.status >= 200 && xhr.status < 300) {
//将响应体的结果在div中呈现
div.innerText = xhr.responseText;
} else {
alert('请求失败');
}
}
}
}
</script>
</body>
3.5 ajax在IE中的缓冲问题以及解决方法
在IE浏览器中只要成功的请求响应过结果一次,就会将结果缓存在浏览器中,即使服务端响应的结果更新了;
客户端请求到的数据仍然是上一次的结果,解决办法只需要每一次发送请求时添加时间戳。
xhr.open('get', 'http://127.0.0.1/server?time=' + Date.now());
3.6 ajax中json格式数据的处理
mime类型:https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types
需求:文本框失焦时发送ajax请求
3.6.1 手动转换
<body>
<input type="text">
<span></span>
<script>
//1、获取元素
let ipt = document.querySelector('input');
let span = document.querySelector('span');
//2、绑定失焦事件
ipt.onblur = function () {
//3、发送ajax请求
const xhr = new XMLHttpRequest();
xhr.open('get', 'http://127.0.0.1/json-server');
xhr.send();
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if (xhr.status >= 200 && xhr.status < 300) {
//将json字符串转换成json对象
const data = JSON.parse(xhr.responseText);
//判断
if (data.errno == 1) {
ipt.style.border = "1px solid red";
span.innerText = data.errmsg;
}
}
}
}
}
</script>
</body>
app.get('/json-server',(request,response)=>{
//响应结果 json格式的响应体
let data = {
errno : 1,
errmsg : '用户名已经存在'
}
//将json对象转换成json字符串
let str = JSON.stringify(data);
//允许来自于不同的主机来向我发送跨域请求,必须设置
response.setHeader('Access-Control-Allow-Origin','*');
//设置响应体
response.end(str);
});
3.6.2 自动转换
第一步:预先设置响应体的结果类型为json
xhr.responseType = 'json';
第二步:获取响应体数据使用response
console.log(xhr.response); #在这里response会根据设置类型自动变化;responseText始终为响应字符串
案例1:网络列表数据的获取
<body>
<button>点击获取数据列表</button>
<ul></ul>
<script>
//获取元素
let btn = document.querySelector('button');
let ul = document.querySelector('ul');
//2、绑定事件
btn.addEventListener('click', () => {
const xhr = new XMLHttpRequest();
xhr.responseType = 'json';
xhr.open('get', 'http://iwenwiki.com/api/blueberrypai/getIndexTravelnote.php');
xhr.send();
xhr.onreadystatechange = function () {
//判断
if (xhr.readyState == 4) {
if (xhr.status >= 200 && xhr.status < 300) {
let data = xhr.response;
data.travelnote.forEach(item => {
//创建li节点对象
let liNode = document.createElement('li');
//修改li标签的文本
liNode.innerText = item.title
//ul追加
ul.appendChild(liNode);
})
}
}
}
});
</script>
</body>
案例2:天气数据的查询
注:http://tianqiapi.com/ 需要提前注册
<style>
#result {
width: 300px;
height: 200px;
border: 1px solid #222;
}
</style>
</head>
<body>
<input type="text">
<button>点击查询</button>
<hr>
<div id="result"></div>
<script>
//1、获取元素对象
let ipt = document.querySelector('input');
let btn = document.querySelector('button');
let result = document.querySelector('#result');
//2、绑定事件
btn.addEventListener('click', () => {
let cvalue = ipt.value;
//3、创建ajax请求
let xhr = new XMLHttpRequest();
xhr.responseType = 'json'
xhr.open('get', 'https://spot.yiketianqi.com/?action=city&appid=82294778&appsecret=4PKVFula&province=%E5%B9%BF%E4%B8%9C&city=%E6%B7%B1%E5%9C%B3');
xhr.send();
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if (xhr.status >= 200 && xhr.status < 300) {
let data = xhr.response;
console.log(data);
}
}
}
})
</script>
</body>
3.7 ajax请求超时
xhr.timeout = 2000; //2秒钟之内需要有响应,如果没有响应则执行超时函数
xhr.ontimeout = function () {
alert('不好意思,请求超时了,请等待重试!!');
}
3.8 ajax取消请求
<body>
<button id="timeout">发送超时请求</button>
<button id="cancel">取消请求</button>
<script>
//1、获取元素
let timeout = document.querySelector('#timeout');
let cancel = document.querySelector('cancel');
let xhr; //注意这里不能使用const,因为需要有初始化的值
//2、绑定事件
timeout.onclick = function () {
//也可以判断是否正在发送
if (xhr) {
xhr.abort();
}
//3、发送ajax请求
xhr = new XMLHttpRequest();
xhr.open('get', 'http://127.0.0.1/delay-server');
xhr.send();
//超时时间设置
xhr.timeout = 3000;
xhr.ontimeout = function () {
alert('对不起 请求超时 请重试');
}
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if (xhr.status >= 200 && xhr.status < 300) {
console.log(xhr.response);
}
}
}
}
cancel.onclick = function () {
xhr.abort();
}
</script>
</body>
app.get('/delay-server',(request,response)=>{
setTimeout(()=>{
response.send('delay');
},3000);
});
四、ajax的请求跨域问题
4.1 同源策略
同源策略(Same-Origin Policy)最早由Netspace公司提出,是浏览器的一种安全策略。
同源是指协议
、域名
、端口号
都必须完全相同,两个资源必须来自于同一个服务,
如果违背上述任何一个条件就是跨域
。
4.2 如何解决跨域
4.2.1 JSONP
- JSONP是什么
JSONP(JSON with Padding),是一个非官方的跨域解决方案,
纯粹凭借程序员的聪明才智开发出来,只支持get请求
。
- JSONP怎么工作的?
在网页有一些标签天生具有跨域能力,比如 img、link、iframe、script
JSONP就是利用script标签的跨域能力来发送请求的
。
-
JSONP的使用
动态的创建一个script标签
var script = document.createElement('script');
设置script的src,设置回调函数
script.src = "http://127.0.0.1/jsonp-server?cb=handler";
function handler(data) {
console.log(data);
};
将script添加到body中
document.body.appendChild(script);
在服务端定义url路由规则
app.get('/jsonp-server',(request,response)=>{
let data = '此用户名已经存在';
let cb = request.query.cb;
response.end(`${cb}("${data}")`);
})
案例:客户端发送jsonp跨域请求
<body>
<button>发送jsonp跨域请求</button>
<p></p>
<script>
//声明一个函数(回调函数),函数的作用是对响应体结果进行处理
function handler(data){
//将响应结果显示到p标签中
document.querySelector('p').innerHTML = data;
}
let btn = document.querySelector('button');
btn.onclick = function(){
//创建script标签
let script = document.createElement('script');
//修改script标签的src属性
script.src = "http://127.0.0.1/jsonp-server?cb=handler";
//将script标签添加到body中
document.body.appendChild(script);
}
</script>
</body>
-
jquery发送JSONP请求
<head> <title>jquery发送jsonp请求</title> <script type="text/javascript" src="./jquery-1.12.4.js"></script> </head> <body> <button>jquery发送jsonp请求</button> <script> //获取元素对象 let btn = document.querySelector('button'); //绑定事件 btn.onclick = function(){ $.getJSON('http://127.0.0.1/jsonp-server?cb=?',function(data){ console.log(data); }) } </script> </body>
4.2.2 CORS
-
什么是CORS
CORS(Cross-Origin Resource Sharing),跨域资源共享。
CORS是官方的跨域解决方案,它的特点是
不需要在客户端做任何特殊的操作
,完全在服务器中进行处理,支持get和post请求
。 -
CORS是如何工作的
CORS是
通过设置一个响应头来告诉浏览器
,该请求允许跨域,浏览器收到该响应以后就会对响应放行。 -
CORS的使用
只需要在服务端中设置响应头
app.get('/server',(request,response)=>{
//允许来自于不同的主机来向我发送跨域请求,必须设置
response.setHeader('Access-Control-Allow-Origin','*');
//允许在请求过程中添加自定义请求头,如果不添加只能使用http中默认的一些请求头
//例如:想要添加a:100就不行,所以这句话需要设置上
response.setHeader('Access-Control-Allow-Headers','*');
//设置响应体
response.end('server');
});