// 第一步 创建 xhr 对象 XMLHttpRequest
var xhr = new XMLHttpRequest();
// 第二步 监听 xhr 对象发起的 http 请求状态
// readystate 值发生变化,就会触发,整个请求过程共计触发 4 次
/*
xhr.onreadystatechange = function() {
// 当响应内容接收完毕之后
if (xhr.readyState === 4) {
// 获取响应体的内容
console.log(xhr.responseText);
}
};
*/
// 当响应完成后(已经接收完所有响应内容)触发 load 事件 -- 可以代替 readystatechagne 事件
xhr.onload = function() {
console.log(xhr.responseText);
box.innerHTML = xhr.responseText;
}
// 第三步 进行初始化,为发送http请求做准备 指定请求方式和URL
xhr.open('GET', 'http://localhost:8080/getData');
// 第四步 发送请求
xhr.send();
readyState 的值:
0 初始值
1 open()方法已经调用,请求初始化完毕
2 send()方法已经调用,请求已经发出,并且开始接收响应行和响应头
3 已经开始接收响应体
4 所有的响应内容接收完毕
GET 方式没有请求体,只能通过 URL 携带数据
// 请求初始化 可以将数据拼接到url中
xhr.open('GET', '/addData?a=100&b=200');
// 发送请求 GET方式没有请求体,send()不需要参数
xhr.send();
// 请求初始化 POST 也可以通过 URL 携带数据
xhr.open('POST', '/addData?type=100');
// 在初始化之后请求之前,通过设置请求头的 Content-type 字段,设置请求体的内容类型
xhr.setRequestHeader('Content-type', 'text/plain');
// 发送请求 POST 方式可以指定请求体
xhr.send(msg);
1. 默认的请求体类型,如果不设置请求头字段 Content-type,默认就是该种类型
2. 请求体只要是字符串就可以,后端不会做任何处理
application/x-www-form-urlencoded
1. 需要设置 xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
2. 要求请求体是查询字符串,如 a=100&b=200
3. 点击提交按钮提交表单(非Ajax),如果 Method 是 Post,默认请求体内容就是 x-www-form-urlencoded
application/json
1. 设置设置 xhr.setRequestHeader('Content-type', 'application/json');
2. 要求请求体是 json 格式的字符串
无需发送请求体: GET、HEAD
可以添加请求体: POST、PUT、DELETE、OPTIONS、PATCH
<!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>
<h1>发送请求携带数据</h1>
<hr>
<table>
<tr>
<td>用户名:</td>
<td><input type="text" name="username" id="username"></td>
</tr>
<tr>
<td>密码:</td>
<td><input type="password" name="pwd" id="pwd"></td>
</tr>
<tr>
<td></td>
<td>
<button id="btn1">GET方式提交</button>
</td>
</tr>
<tr>
<td></td>
<td>
<br>
<button id="btn2">POST方式提交 - plain</button> <br>
<button id="btn3">POST方式提交 - urlencoded</button> <br>
<button id="btn4">POST方式提交 - json</button> <br>
<br>
<button id="btn5">PUT方式提交</button> <br>
</td>
</tr>
</form>
<script>
// 获取元素
var userInp = document.querySelector('#username');
var pwdInp = document.querySelector('#pwd');
// 创建 xhr 对象
var xhr = new XMLHttpRequest();
// 监听响应结束的事件
xhr.onload = function() {
alert(xhr.responseText);
};
// 1. 点击按钮 发起 GET 请求, GET方式如何携带数据
var btn1 = document.querySelector('#btn1');
btn1.onclick = function(){
// 将表单的数据拼接到查询字符串中
var msg = `username=${userInp.value}&password=${pwdInp.value}`;
// 请求初始化 可以将数据拼接到url中
xhr.open('GET', '/addData?' + msg);
// 发送请求 GET方式没有请求体,send()不需要参数
xhr.send();
}
// 2. 点击按钮 发起 POST 请求
var btn2 = document.querySelector('#btn2');
btn2.onclick = function() {
// 将表单的数据拼接到查询字符串中
var msg = `username=${userInp.value}&password=${pwdInp.value}`;
// 请求初始化
xhr.open('POST', '/addData?type=100');
// 发送请求
xhr.send(msg);
}
// 3. 点击按钮 发起 POST 请求 指定请求体内容类型 application/x-www-form-urlencoded
var btn3= document.querySelector('#btn3');
btn3.onclick = function(){
// 将表单的数据拼接到查询字符串中
var msg = `username=${userInp.value}&password=${pwdInp.value}`;
// 请求初始化
xhr.open('POST', '/addData?type=200');
// 在请求初始化之后,发送请求之前,设置请求头
xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
// 发送请求
xhr.send(msg);
}
// 4. 点击按钮 发起 POST 请求, 指定请求体内容类型是 application/json
var btn4= document.querySelector('#btn4');
btn4.onclick = function() {
// 定义对象
var obj = {
username: userInp.value,
password: pwdInp.value
}
// 请求初始化
xhr.open('POST', '/addData?type=300');
// 在请求初始化之后,发送请求之前,设置请求头
xhr.setRequestHeader('Content-type', 'application/json');
// 发送请求 请求体要求是 json 格式的字符串
xhr.send(JSON.stringify(obj));
};
// 5. 点击按钮 发起 PUT请求, 指定请求体内容类型是 application/json
var btn5= document.querySelector('#btn5');
btn5.onclick = function() {
// 定义对象
var obj = {
username: userInp.value,
password: pwdInp.value
}
// 请求初始化
xhr.open('PUT', '/addData?type=400');
// 在请求初始化之后,发送请求之前,设置请求头
xhr.setRequestHeader('Content-type', 'application/json');
// 发送请求 请求体要求是 json 格式的字符串
xhr.send(JSON.stringify(obj));
};
</script>
</body>
</html>
1. 请求体(send()的方法的参数)除了是字符串,也可以是 formData 对象
2. 如果请求体是 FormData 对象,浏览器会自动设置请求头字段 Content-type 为 multipart/form-data
// 方式一 创建 空的 FormData,再添加数据,可以添加文件数据或者字符串数据
var fd = new FormData();
fd.append('message', msgInput.value);
fd.append('avator', avatorInput.files[0]);
fd.append('content', 'hello ajax');
// 方拾二 根据表单元素创建 FormData 会包含表单中所有的信息
var fd = new FormData(uploadForm);
append()
set()
delete()
get()
getAll()
<!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>
<h1>Ajax 上传文件</h1>
<form id="uploadForm" onsubmit="return false">
<input type="text" placeholder="留言" name="msg" id="msg"> <br><br>
<input type="file" name="avator" id="avator"><br><br>
<button id="btn">上传</button>
</form>
<script>
// 获取相关元素
var uploadForm = document.querySelector('#uploadForm');
var msgInput = document.querySelector('#msg');
var avatorInput = document.querySelector('#avator');
var btn = document.querySelector('#btn');
// 创建 xhr 对象
var xhr = new XMLHttpRequest();
// 设置响应成功之后的回调
xhr.onload = function() {
alert(xhr.responseText);
}
// 点击按钮 执行上传
btn.onclick = function() {
// 创建 空的 FormData,再添加数据
// var fd = new FormData();
// fd.append('message', msgInput.value);
// fd.append('avator', avatorInput.files[0]);
// fd.append('content', 'hello ajax');
// 根据表单元素创建 FormData
var fd = new FormData(uploadForm);
// 请示初始化
xhr.open('POST', '/upload')
// 发送请求
xhr.send(fd);
};
</script>
</body>
</html>
// 响应行
xhr.status; // 响应状态码
xhr.statusText; // 响应状态描述
// 响应头
xhr.getResponseHeader('响应头字段'); // 获取指定字段的响应头的信息
xhr.getAllResponseHeaders(); // 获取所有的响应头信息
// 响应体
xhr.responseText; // 获取响应体体符串
xhr.response; // 获取响应体字符串,如果响应体是特殊格式的字符串,会进行处理,前提是设置xhr.responseType = ' ';
设置响应头,告知浏览器响应体的内容类型是 json 格式
Content-type: application/json;charset=utf-8
// 监听响应结束的回调函数、
xhr.onload = function() {
// 将响应体中 json 格式的字符串处理成对象
var resData = JSON.parse(xhr.responseText);
}
xhr.responseType = 'json';
xhr.onload = function() {
xhr.response; // 直接得到处理好的对象
}
<!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>
#box p {
width: 600px;
padding: 10px;
border: 2px dashed #ccc;
}
</style>
</head>
<body>
<h1>响应 json 格式的数据</h1>
<button id="btn1">请求数据 第一种处理josn的方式</button>
<button id="btn2">请求数据 第二种处理json的方式</button>
<hr>
<div id="box">
</div>
<script>
// 获取相关元素
var btn1 = document.querySelector('#btn1');
var btn2 = document.querySelector('#btn2');
var box = document.querySelector('#box');
// 创建 xhr 对象
var xhr = new XMLHttpRequest();
// 点击第一个按钮 自行处理响应体内容
btn1.onclick = function() {
// 请求初始化
xhr.open('GET', '/getUsers');
// 发送请求
xhr.send();
// 监听响应结束的回调函数、
xhr.onload = function() {
// 将响应体中 json 格式的字符串处理成对象
var resData = JSON.parse(xhr.responseText);
// 遍历数组
resData.forEach(function(item, index){
// 创建元素
var pEle = document.createElement('p');
pEle.innerHTML = `序号:${index},姓名:${item.name},年龄:${item.age},地址:${item.address}`;
// 添加元素
box.appendChild(pEle);
})
}
}
// 点击第二个按钮
btn2.onclick = function() {
// 请求初始化
xhr.open('GET', '/getUsers');
// 发送请求
xhr.send();
// 设置响应体类型
xhr.responseType = 'json';
// 监听响应结束的回调函数、
xhr.onload = function() {
var resData = xhr.response;
// // 遍历数组
resData.forEach(function(item, index){
// 创建元素
var pEle = document.createElement('p');
pEle.innerHTML = `序号:${index},姓名:${item.name},年龄:${item.age},地址:${item.address}`;
// 添加元素
box.appendChild(pEle);
})
}
}
</script>
</body>
</html>
// 发送请求
xhr.send();
// 发送请求之后,设置单次定时,如果时间到了还没有接收到响应,中断请求
setTimeout(function(){
// 判断如果没有响应结束
if (xhr.readyState !== 4) {
xhr.abort(); // 中断请求
alert('请求超时!');
}
}, 5000);
// 监听响应超时的事件
xhr.ontimeout = function(){
alert('响应超时!');
}
// 请求初始话
xhr.open('GET', '/getInfo');
// 发送请求之前设置超时时间
xhr.timeout = 5000;
// 发送
xhr.send();
readystatechange 触发至少 4 次
loadstart 开始请求的时候触发,此时 readyState 的值是 1
load 响应结束的时候触发,此时 readyState 的值是 4,请求成功触发
error 请求失败触发,应用层面的错误也算是请求成功(如 404错误),只有网络错误才算请求失败
loadend 响应结束之后触发,不论请求是否成功都会触发
progress 开始接收响应内容之后,被触发多次,该事件的回调函数可以获取一个 progressEvent 对象
相关事件的触发顺序: loadstart、progress(可能会触发多次)、 load/error、loadend
progress 事件的回调函数可以获取一个 progressEvent 对象,该对象有如下属性:
loaded 表示当前已经下载的字节数
total 表示响应内容的总长度
两者区别:
1. 异步请求,请求发送之后,其他同步操作继续执行; 当获取响应之后触发回调函数,回调函数进入回调队列等待主线程空闲执行
2. 同步请求,请求发送之后,其他的同步操作必须等到,响应结束之后才能继续执行
如何发送同步请求:
open() 方法的第三个参数是布尔值,true 表示异步请求,false 表示同步请求,默认值是 true。
1)XMLHttpRequest 对象简称 XHR 对象。
2)XMLHttpRequest 对象提供了对 HTTP 协议的完全的访问,包括做出 POST 和 HEAD 请求以及普通的 GET 请求的能力。
3)XMLHttpRequest 可以同步或异步地返回 Web 服务器的响应,并且能够以文本或者一个 DOM 文档的形式返回内容。
4)尽管名为 XMLHttpRequest,它并不限于和 XML 文档一起使用,它可以接收任何形式的文本文档。
使用构造函数 XMLHttpRequest 就可以创建一个 XHR 对象。
let xhr = new XMLHttpRequest();
注意:在古老的 IE 浏览器中(如:IE6),需要使用其他方式来创建 XHR 对象。
// IE5、IE6
let xhr = new ActiveXObject("Microsoft.XMLHTTP");
属性名 | 含义 |
---|---|
readyState | 返回一个数字,表示请求的状态: 0 – UNSET – XHR对象已创建或已被 abort() 方法重置。 1 – OPENDED – open() 方法已经被调用。2 – HEADERS_RECEIVED – send() 方法已经被调用,并且响应头和响应状态已经可获得。 3 – LOADING – 下载中, responseText 属性已经包含部分数据。 4 – DONE – 所有响应数据接收完毕。 |
status | 响应状态码,如 404、200 等。 |
statusText | 响应状态码的文本描述,如 200 对应的是 “OK”。 |
responseXML | 接收格式为 XML 的响应数据,返回一个 document 对象。 |
responseText | 获取响应文本,返回一个字符串。 |
responseType | 用于设置响应内容的类型 xhr2 |
response | 返回的类型取决于 responseType 的设置。 xhr2 |
timeout | 设置超时时间。xhr2 |
方法名 | 含义 |
---|---|
open() | 初始化 HTTP 请求,用来指定请求方式和 URL。 xhr.open(method, url, [async], [user], [password]) |
send() | 发送 HTTP 请求,参数可以设置请求体,没有请求体无需设置参数。 |
setRequestHeader() | 设置 HTTP 请求头的值。必须在 open() 之后、send() 之前调用。 |
abort() | 如果请求已被发出,则立刻中止请求。 |
getAllResponseHeaders() | 以字符串形式返回所有的响应头。 |
getResponseHeader() | 返回指定的响应头。 |
事件名 | 含义 |
---|---|
readystatechange | readyState 属性值发生变化触发该事件。 |
abort | 请求终止时触发。 |
error | 请求遇到错误时触发。注意,只有发生了网络层级别的异常才会触发此事件。 |
loadstart | 接收到响应数据时触发。 xhr2 |
load | 请求成功完成时触发。xhr2 |
loadend | 当请求结束时触发, 无论请求成功 ( load ) 还是失败 (abor 或 error )。xhr2 |
progress | 当请求接收到更多数据时,周期性地触发。xhr2 |
timeout | 在预设时间内没有接收到响应时触发。xhr2 |
在服务端进行设置
添加一个响应头,设置允许的 域名
Access-Control-Allow-Origin: http://localhost:8080
# 允许前面页面的域名是http://localhost:8080,才能跨域
Access-Control-Allow-Origin:*
# 允许所有的域名都可以跨域
****实现基础:
***利用 script 标签也可以发送请求,天然支持跨域, script 会把响应到的内容作为 js 代码执行*******
实现步骤:(前端)
1. 创建 script 标签
2. 指定 script 标签的 src 属性值,src 的属性值就是请求地址, 把函数名通过url中的查询字符串传给后端
3. 把 script 标签添加到 body 中
4. 再把 script 标签从 body 中移除
5. 定义获取数据的函数,该函数会被后端响应的内容调用,把数据传进来
注意: 在 script 添加到 body 中的瞬间,发起请求,接收响应,调用了函数
实现步骤:(后端)
1. 从 url 中的查询字符串里取出函数名
2. 响应体内容是 js 代码,调用函数的js代码,把数据变为json格式作为函数的参数
3. 做出响应
只支持 GET 请求
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>jsonp</title>
</head>
<body>
<h1>JSONP</h1>
<hr>
<button id="btn">请求数据</button>
<script>
/*
后端给前端接口文档
jsonp 请求
地址: http://localhost:8080/getdata02?cb=函数名
*/
// 点击按钮 发送请求
var btn = document.querySelector('#btn');
btn.onclick = function(){
// 创建 script 标签
var scriptEle = document.createElement('script');
// 设置 script 标签的src 属性
scriptEle.src = 'http://localhost:8080/getdata02?cb=getData';
// 将 script 标签添加到文档结构, 添加到文档结构的那一刻,js代码就行了
document.body.appendChild(scriptEle);
// script 用完就销毁
document.body.removeChild(scriptEle);
};
function getData(data) {
console.log(data);
}
</script>
</body>
</html>
JSONP后端操作
// 导入模块
const path = require('path');
const express = require('express');
// 创建 express 实例
const app = express();
// 1. 同源策略 -----------------------------------------------------------------------
// 同源策略
app.get('/01-page', (req, res) => {
res.sendFile(path.join(__dirname, '01-CORS.html'));
});
// 接收 ajax 请求
app.get('/getdata01', (req, res) => {
// 设置响应头 允许跨域; 可以允许的前端页面的域名
// res.setHeader('Access-Control-Allow-Origin', 'http://localhost:8080');
// 允许所有的域名
res.set('Access-Control-Allow-Origin', '*');
res.send('hello ajax');
});
**// 2. jsonp -----------------------------------------------------------------------
// 打开 02-jsonp解决跨域.html 静态文件
app.get('/02-page', (req, res) => {
res.sendFile(path.join(__dirname, 'jsonp请求.html'));
});**
// 接收到是 jsonp 的请求
app.get('/getdata02', (req, res) => {
// // 定义数据
const users = [
{name:'李华0', age:90, address:'上海'},
{name:'李华1', age:90, address:'上海'},
{name:'李华2', age:90, address:'上海'},
{name:'李华3', age:90, address:'上海'},
{name:'李华4', age:90, address:'上海'}
];
//从 url 中得到函数名
let method = req.query.cb;
// 定义响应体 js 代码
let body = `${method}(${JSON.stringify(users)})`;
//字符串内容会被当作js代码执行,前端拿到的是一个数组。
res.send(body)
// res.send(`getInfo(${JSON.stringify(users)})`)
});
// 开启服务
app.listen(8080, () => {
console.log(‘HTTP服务启动成功,端口号 8080’);
})
## 3. jQuery 中使用 Ajax
### 3.1 发起 ajax 请求的方法
```js
$.get(url, [data], callback, [dataType])
url: 请求地址
data: 发给服务端的数据 形式可以是字符串也可以是对象,自动把数据拼接到url上
'a=100&b=200'
{a:100,b:200}
callback:成功接收到响应之后回调函数
dataType: 指定响应内容的格式,回调获取内容自动处理
$.post(url, [data], callback, [dataType])
url: 请求地址
data: 发给服务端的数据 形式可以是字符串也可以是对象,自动把数据添加到请求体
'a=100&b=200'
{a:100,b:200}
callback:成功接收到响应之后回调函数
dataType: 指定响应内容的格式,回调获取内容自动处理
$.ajax() 发起任意方式的请求
$.ajax({
url: '/data', // url
type: 'POST', // 请求方式
// data: {a:100,b:200}, // 发送给服务端的数据(默认请求体类型是application/x-www-form-urlencoded)
//如果post请求后台限定了为application/json,
//当设置contentType为application/json还是出错时,把data也要转换一下
contentType: 'application/json',//指定请求内容的类型
data:JSON.Stringify({a:100,b:200})
success: function(data){ // 响应成功之后的回调函数
alert(data);
},
dataType: 'json' // 指定响应内容的类型
})
$('input').serialize(); // 返回字符串 形式 'a=100&b=200', 直接作为 $.get $.post $.ajax 的参数
$.getJSON('http://127.0.0.1:8080/product-data?cb=?', function(data) {
console.log(data);
});