JavaScript XmlHttpRequest
XmlHttpRequest
这是原生的一种发送网络请求的技术,存在非常久的方案。
基本上所有框架对于网络请求的部分都是基于它来做的。
方法介绍
open
open()
用于创建请求(单纯创建,并不发送)
注意:如果是
open()
的method
为GET
,则需要自带参数。
参数 | 说明 |
---|---|
method | 请求方式 |
url | 请求地址 |
async | 是否异步 |
send
send()
用于发送请求,如果你的open()
的method
是GET
,则这里可以填上null
。
参数 | 说明 |
---|---|
body | 要发送的数据(字符串类型) |
function ajax() {
let xhr = new XMLHttpRequest();
xhr.open("GET", "http://127.0.0.1:8000/", true);
xhr.send(null);
}
setRequestHeader
用于设置请求头,一般我们会指定编码方式。
参数 | 说明 |
---|---|
header | 请求头的key(字符串类型) |
vlaue | 请求头的value(字符串类型) |
getAllResponseHeaders
用于获取响应头,返回所有的响应头数据(字符串类型)。
getResponseHeader
获取响应头中指定header
的值,返回该响应头的数据(字符串类型)。
参数 | 描述 |
---|---|
header | 响应头的key(字符串类型) |
abort
终止请求。
属性介绍
status
状态码,如200/404
等等。
readyState
这是一个整数类型的状态值,使用XmlHttpRequest
时共有5种状态。
状态值 | 描述 |
---|---|
0 | 未初始化,尚未调用open()方法 |
1 | 启动,调用了open()方法,未调用send()方法 |
2 | 发送,已经调用了send()方法,未接收到响应 |
3 | 接收,已经接收到部分响应数据 |
4 | 完成,已经接收到全部响应数据 |
statesText
状态文本(字符串),如:OK、NotFound...
responseText
这是服务器返回的数据(字符串类型)
XmlDocument
XmlDocument
与responseXML
一样,都是 服务器返回的数据(Xml
对象)
回调函数
onreadystatechange
当readyState
的值改变时自动触发执行其对应的函数(回调函数)
有了这个回调函数,我们就可以开始做一个原生的ajax
了。
使用方式
简单封装
这下面是一个最简单的封装。
function ajax() {
let xhr = new XMLHttpRequest();
xhr.open("GET", "http://127.0.0.1:8000/?username=Yunya", true);
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset-UTF-8');
xhr.send(null);
// 如果是POST请求,则 数据格式为 xhr.send('n1=1;n2=2;');
xhr.onreadystatechange = function(){
console.log(xhr.status);
if (xhr.readyState == 4 && xhr.status==200){
console.log("请求成功");
console.log(xhr.responseText);
}
else if(xhr.status == 404){
console.log("请求失败");
}
else if(xhr.status == 500){
console.log("服务器内部错误")
}
}
}
初级封装
下面是融合了POST
和GET
的封装,基本使用与jQuery
的ajax
相同
(function () {
class Ajax {
constructor({ url, type, dataType, data, contentType, success, error }) {
this.url = url;
this.type = type;
this.data = data;
this.contentType = !!contentType == true ? contentType : 'application/x-www-form-urlencoded';
this.success = typeof success == "function" ? success : (res) => { };
this.error = typeof error == "function" ? error : (res) => { };
this.xhr = null;
this.send_data = null;
this.init();
}
init() {
// 第一步,处理上传的数据格式
this.dataFormat();
// 第二步:如果是GET提交,则send()中不能有任何数据
if (this.type == "GET") {
this.getAjax();
} else if (this.type == "POST") {
this.postAjax();
}
// 第三步:判断后端返回信息
this.callbackAjax();
}
dataFormat() {
this.send_data = Object.entries(this.data).reduce((prev, value, index, array) => {
if (array.length - 1 == index) {
return prev += `${value[0]}=${value[1]}`
}
else {
return prev += `${value[0]}=${value[1]}&`
}
}, "")
}
getAjax() {
this.url = this.url.concat('?', this.send_data,);
this.xhr = new XMLHttpRequest();
this.xhr.open(this.type, this.url, true);
this.xhr.setRequestHeader("Content-Type", this.contentType)
this.xhr.send(null);
}
postAjax() {
this.xhr = new XMLHttpRequest();
this.xhr.open(this.type, this.url, true);
this.xhr.setRequestHeader("Content-Type", this.contentType)
this.xhr.send(this.send_data);
}
callbackAjax() {
this.xhr.onreadystatechange = () => {
if (this.xhr.readyState == 4 && this.xhr.status == 200) {
if (this.dataType == "JSON") {
this.success(JSON.parse(this.xhr.responseText));
} else {
this.success(this.xhr.responseText);
}
} else if (this.xhr.status == 404) {
this.error("请求失败,检查IP与PORT");
} else if (this.xhr.status == 500) {
this.error("请求失败,服务器内部错误");
}
}
}
}
window.Ajax = Ajax;
}())
// 调用方式 new Ajax() 传入参数即可
文件上传
由于上面不支持文件上传,所以我们需要再做一个有文件上传功能的AJAX
。
(function () {
class Ajax {
constructor({ url, type, dataType, data, contentType, success, error,file=false }) {
this.url = url;
this.type = type;
this.data = data;
this.contentType = !!contentType == true ? contentType : 'application/x-www-form-urlencoded';
this.success = typeof success == "function" ? success : (res) => { };
this.error = typeof error == "function" ? error : (res) => { };
this.xhr = null;
this.send_data = null;
this.file = file; // 是否支持文件上传
this.init();
}
init() {
// 第一步,处理上传的数据格式
this.dataFormat();
// 第二步:如果是GET提交,则send()中不能有任何数据
if (this.type == "GET") {
this.getAjax();
}else if (this.file){
this.fileAjax();
}
else if (this.type == "POST") {
this.postAjax();
}
// 第三步:判断后端返回信息
this.callbackAjax();
}
dataFormat() {
this.send_data = Object.entries(this.data).reduce((prev, value, index, array) => {
if (array.length - 1 == index) {
return prev += `${value[0]}=${value[1]}`
}
else {
return prev += `${value[0]}=${value[1]}&`
}
}, "")
}
getAjax() {
this.url = this.url.concat('?', this.send_data,);
this.xhr = new XMLHttpRequest();
this.xhr.open(this.type, this.url, true);
this.xhr.setRequestHeader("Content-Type", this.contentType);
this.xhr.send(null);
}
postAjax() {
this.xhr = new XMLHttpRequest();
this.xhr.open(this.type, this.url, true);
this.xhr.setRequestHeader("Content-Type", this.contentType);
this.xhr.send(this.send_data);
}
fileAjax(){
// 注意,文件上传只能是POST形式
this.xhr = new XMLHttpRequest();
this.xhr.open("POST", this.url,true);
this.xhr.send(this.data); // 注意,这里是上传的this.data
}
callbackAjax() {
this.xhr.onreadystatechange = () => {
if (this.xhr.readyState == 4 && this.xhr.status == 200) {
if (this.dataType == "JSON") {
this.success(JSON.parse(this.xhr.responseText));
} else {
this.success(this.xhr.responseText);
}
} else if (this.xhr.status == 404) {
this.error("请求失败,检查IP与PORT");
} else if (this.xhr.status == 500) {
this.error("请求失败,服务器内部错误");
}
}
}
}
window.Ajax = Ajax;
}())
json格式
如果需要发送JSON
格式的数据,则我们还需要进行改进。
首先要明确,GET
提交方式不要使用JSON
格式的数据进行发送。
如果你后端是使用Django
的话,那么json
格式不会存放进request.POST
中,而是存放request.body
中。
说明:
file
为true
时,代表上传文件,json_data
为true
时,代表前端发送json
数据至后端,dataType
为JSON
时,代表自动转换后端传过来的json
格式数据。
(function () {
class Ajax {
constructor({ url, type, dataType, data, contentType, success, error,file=false,json_data=false }) {
this.url = url;
this.type = type;
this.data = data;
this.contentType = !!contentType == true ? contentType : 'application/x-www-form-urlencoded';
this.success = typeof success == "function" ? success : (res) => { };
this.error = typeof error == "function" ? error : (res) => { };
this.xhr = null;
this.send_data = null;
this.file = file; // 是否支持文件上传
this.json_data = json_data;
this.init();
}
init() {
// 如果是GET+JSON格式发送则抛出异常
if(this.json_data && this.type=='GET'){
throw new Error("不可使用GET方式提交JSON数据");
}else if(this.json_data && this.file ){
throw new Error("提交文件不可使用JSON数据");
}
// 第一步,处理上传的数据格式
if(!this.json_data){
this.dataFormat();
}
else{
this.dataJson();
}
// 第二步:如果是GET提交,则send()中不能有任何数据
if (this.type == "GET") {
this.getAjax();
}else if (this.file){
this.fileAjax();
}
else if (this.type == "POST") {
this.postAjax();
}
// 第三步:判断后端返回信息
this.callbackAjax();
}
dataFormat() {
this.send_data = Object.entries(this.data).reduce((prev, value, index, array) => {
if (array.length - 1 == index) {
return prev += `${value[0]}=${value[1]}`
}
else {
return prev += `${value[0]}=${value[1]}&`
}
}, "")
}
dataJson(){
this.send_data = JSON.stringify(this.data);
}
getAjax() {
this.url = this.url.concat('?', this.send_data,);
this.xhr = new XMLHttpRequest();
this.xhr.open(this.type, this.url, true);
this.xhr.setRequestHeader("Content-Type", this.contentType);
this.xhr.send(null);
}
postAjax() {
this.xhr = new XMLHttpRequest();
this.xhr.open(this.type, this.url, true);
// 判断是否发送JSON数据格式
if (this.json_data){
this.xhr.setRequestHeader("HTTP_X_REQUESTED_WITH","XMLHttpRequest");
this.xhr.setRequestHeader("Content-Type","application/json");
}else{
this.xhr.setRequestHeader("Content-Type", this.contentType);
}
this.xhr.send(this.send_data);
}
fileAjax(){
// 注意,文件上传只能是POST形式
this.xhr = new XMLHttpRequest();
this.xhr.open("POST", this.url,true);
this.xhr.send(this.data); // 注意,这里是上传的this.data
}
callbackAjax() {
this.xhr.onreadystatechange = () => {
if (this.xhr.readyState == 4 && this.xhr.status == 200) {
if (this.dataType == "JSON") {
this.success(JSON.parse(this.xhr.responseText));
} else {
this.success(this.xhr.responseText);
}
} else if (this.xhr.status == 404) {
this.error("请求失败,检查IP与PORT");
} else if (this.xhr.status == 500) {
this.error("请求失败,服务器内部错误");
}
}
}
}
window.Ajax = Ajax;
}())