- 一、ajax简介
- 二、XMLHttpRequest 的使用及分析
- 三、 实例对象可用的属性
- 3.5 timeout 和 ontimeout
- 四、实例对象的可用方法
- 4.4 overrideMimeType() - 实在没搞懂
- 五、实例对象的事件
- 5.2 onloadstart、onprogress、onload、onloadend
- 5.3 ontimeout
-ajax教程:https://www.tutorialspoint.com/ajax/index.htm
Demo地址: https://gitee.com/hebing_myproject/xmlhttprequest-demo
MDN参考地址:https://developer.mozilla.org/zh-CN/docs/Web/API/XMLHttpRequest
XMLHttpRequest标准:https://xhr.spec.whatwg.org/
XMLHttpRequest Level 2 使用指南:http://www.ruanyifeng.com/blog/2012/09/xmlhttprequest_level_2.html
Introduction to XMLHttpRequest Level 2: https://dev.opera.com/articles/xhr2/#xhrprogressevents
一、ajax简介
AJAX 是一种在无需重新加载整个网页的情况下,能够更新部分网页的技术。AJAX 即 Asynchronous JavaScript and XML. AJAX 通过在后台与服务器进行少量数据交换,使网页实现异步更新。这意味着可以在不重载整个页面的情况下,对网页的某些部分进行更新。传统的网页(不使用 AJAX)如果需要更新内容,必须重载整个页面。
1.1 AJAX 如何工作
二、XMLHttpRequest 的使用及分析
2.1 XMLHttpRequest 的简单使用
如下 是使用浏览器提供的XMLHttpRequest 类实现的 ajax 。简单总结:
- 创建一个 XMLHttpRequest 对象;
- 调用XMLHttpRequest 的 open(method, url, ) 方法 创建一个请求,open方法的两个参数,method表示 请求方式GET/POST等。url 表示请求地址(此方法有多个重载,后面详说);
- 调用 XMLHttpRequest 的 send 发放发送一个请求;
- 定义 XMLHttpRequest 的 onreadystatechange 事件方法,监听XMLHttpRequest请求的状态;
根据请求返回的 HTTP 状态码做对应的处理
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>XMLHttpRequest的第一次使用</title>
<script src="../js/jquery-3.1.0.js"></script>
<script src="../js/commonUtil.js"></script>
</head>
<body>
<h1>Just test</h1>
<button id="get-data">XMLHttpRequest的第一次 - 从服务器获取数据</button>
</body>
<script>
//给btn绑定一个点击事件,点击的时候通过ajax从后台获取数据
$("#get-data").on("click", function() {
//1. 创建一个 XMLHttpRequest 对象
var request = new XMLHttpRequest();
//2. 准备发送请求的数据: url
var url = $.rootPath + "first/try/string";
var method = "GET";
//3. 调用XMLHttpRequest 的 open 方法 创建一个请求
request.open(method, url);
//4. 调用 XMLHttpRequest 的 send 发放发送一个请求
request.send(null);
//5. 为对象添加onreadystatechang响应函数
request.onreadystatechange = function() {
//6. 判断响应是否完成: XMLHttpRequest 对象的响应值 readyState 为4时,响应完成
if (request.readyState === 4) {
//7. 判断响应是否可用: XMLHttpRequest 对象的status 的值为200
if (request.status == 200) { //请求响应成功
//8. 处理响应结果
alert(request.responseText);
}
}
}
})
</script>
</html>
2.2 XMLHttpRequest 实例对象的分析
在浏览器打印XMLHttpRequest 的实例对象,其属性如下图。包含部分可用的属性 和 可自定义的回调函数。且这些属性在原型对象中均存在,所以以下的分析只针对原型对象进行。
其中隐式原型对象 proto的属性如下, 原型对象提供了三种属性可以使用(自己分类定义的,暂且这么叫吧):实例对象可自定义的回调函数;
- 实例对象可直接使用的方法;
- 实例对象的可用属性。
后续内容将分开介绍 XMLHttpRequest 的 所有属性,方法和事件。
三、 实例对象可用的属性
从以上打印出的实例对象的属性中可以看出,XMLHttpRequest 实例对象的可用属性有 readyState、response、responseText、responseType、responseURL、responseXML、status、statusText、timeout等。
注:**前面几个DONE、HEADERS_RECEIVED、LOADING、OPENED、UNSET 其实就是 **readyState的各个状态值的常量。
3.1 readyState(只读)
readyState 属性返回一个 XMLHttpRequest 代理当前所处的状态。一个 XHR 代理总是处于下列状态中的一个:
- UNSENT:XMLHttpRequest 代理已被创建, 但尚未调用 open() 方法。
- OPENED:open() 方法已经被触发。在这个状态中,可以通过 setRequestHeader() 方法来设置请求的头部, 可以调用 send() 方法来发起请求。
- HEADERS_RECEIVED:send() 方法已经被调用,响应头也已经被接收(调用send()方法后,readyState的值并没有变成 2,而是在 onreadystatechange 才能拿到,也就是所获得头部只能在onreadystatechange方法中)。
- LOADING:响应体部分正在被接收。如果 responseType 属性是“text”或空字符串, responseText 将会在载入的过程中拥有部分响应数据。
DONE:请求操作已经完成。这意味着数据传输已经彻底完成或失败。
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>查看readyState的5个状态的触发时间</title> <script src="../../js/jquery-3.1.0.js"></script> <script src="../../js/commonUtil.js"></script> </head> <body> <h1>测试 - 查看各个状态的触发时间</h1> <button id="get-data">查看各个状态的触发出发时间</button> </body> <script> //给btn绑定一个点击事件,点击的时候通过ajax从后台获取数据 $("#get-data").on("click", function() { var xhr = new XMLHttpRequest(); console.log("创建了xhr对象:" + xhr.readyState); //0 : XMLHttpxhr 代理已被创建 var url = $.rootPath + "ready/state/check"; var method = "GET"; xhr.open(method, url); console.log("调用了open方法:" + xhr.readyState); //1: open() 方法已经被触发 在这个状态中,可以通过 setxhrHeader() 方法来设置请求的头部, 可以调用 send() 方法来发起请求。 xhr.send(null); console.log("调用了send方法:" + xhr.readyState); // 1: 此时状态还是1 xhr.onreadystatechange = function() { console.log("onreadystatechange 回调方法:" + xhr.readyState); // 2,3,4: 此处在状态变为2,3,4时都会调用 onreadystatechange 回调 if (xhr.readyState === 4 && xhr.status == 200) { console.log(xhr.responseText); } } }) </script> </html>
3.2 response(只读) 和 responseType
response 是一个对象,其类型取决于 responseType 的值。可以通过设置 responseType 的值,以便通过特定的类型请求数据。 responseType 要在**调用 open() 初始化请求之后调用,并且要在调用 send() 发送请求到服务器之前调用**。
responseType 属性是一个枚举类型的属性,返回响应数据的类型。它允许我们手动的设置返回数据的类型。如果我们将它设置为一个空字符串,它将使用默认的”text”类型。
在工作环境(Work Environment)中将responseType的值设置为”document”通常会被忽略. 当将responseType设置为一个特定的类型时,你需要确保服务器所返回的类型和你所设置的返回值类型是兼容的。那么如果两者类型不兼容呢?恭喜你,你会发现服务器返回的数据变成了null,即使服务器返回了数据。还有一个要注意的是,给一个同步请求设置responseType会抛出一个InvalidAccessError 的异常。
response 对象与responseType的值得对应关系如下
responseType | response |
---|---|
“” (默认值) | responseType 为空字符串时,采用默认类型 DOMString ,与设置为 text 相同。 |
arraybuffer | response 是一个包含二进制数据的 JavaScript ArrayBuffer |
blob | response 是一个包含二进制数据的 Blob 对象 。 |
document | response 是一个 HTML Document 或 XML XMLDocument ,这取决于接收到的数据的 MIME 类型。 |
json | response 是一个 JavaScript 对象。这个对象是通过将接收到的数据类型视为 JSON 解析得到的。 |
text | response 是一个以 DOMString 对象表示的文本。 |
ms-stream(**未标准化**) | response 是下载流的一部分;此响应类型仅允许下载请求,并且仅受 Internet Explorer 支持。 |
3.3 responseText(只读)、responseXML(只读) 、responseURL(只读)
response是接收接口返回数据的属性,器类型会根据 responseType 设置的不同而不同,3.2节中已有详细的内容,此处指测试 responseText 和 responseXML
responseText 和 responseXML都是只读属性。
3.3.1 responseText 只有在 responseType 的值为 “” 或者 text 时才有值,其他情况下报错。
代码
function bindFun() {
$("#response-text").on("click", {
responseType : "text",
url : "text"
}, sendRequest);
$("#response-not-text").on("click", {
responseType : "blob",
url : "not/text"
}, sendRequest);
}
/**
requestType: 请求方式
url:请求地址
*/
function sendRequest(event) {
var responseType = event.data.responseType;
var inurl = event.data.url;
console.log("responseType -> " , responseType);
var xhr = new XMLHttpRequest();
var url = $.rootPath + curModule + inurl;
var method = "GET";
xhr.open(method, url);
xhr.responseType = responseType; //responseType 是可读可写属性, 直接通过赋值的方式设置
xhr.send(null);
xhr.onreadystatechange = function() {
if (xhr.readyState == 4 && xhr.status === 200) {
console.log("responseText -> ",xhr.responseText)
}
}
}
3.3.2 responseXML 只有在 responseType 的值为 document 时才有值,其他情况下报错。
function bindFun() {
$("#response-document").on("click", {
responseType : "document",
url : "document"
}, sendRequest);
$("#response-not-document").on("click", {
responseType : "blob",
url : "not/document"
}, sendRequest);
}
/**
requestType: 请求方式
url:请求地址
*/
function sendRequest(event) {
var responseType = event.data.responseType;
var inurl = event.data.url;
console.log("responseType -> " , responseType);
var xhr = new XMLHttpRequest();
var url = $.rootPath + curModule + inurl;
var method = "GET";
xhr.open(method, url);
xhr.responseType = responseType; //responseType 是可读可写属性, 直接通过赋值的方式设置
xhr.send(null);
xhr.onreadystatechange = function() {
if (xhr.readyState == 4 && xhr.status === 200) {
console.log("responseXML -> ",xhr.responseXML)
}
}
}
3.3.3 responseURL返回经过序列化(serialized)的响应 URL,如果该 URL 为空,则返回空字符串。
function sendRequest(event) {
var responseType = event.data.responseType;
var inurl = event.data.url;
var xhr = new XMLHttpRequest();
var url = $.rootPath + curModule + inurl;
var method = "GET";
xhr.open(method, url);
xhr.responseType = responseType; //responseType 是可读可写属性, 直接通过赋值的方式设置
xhr.send(null);
xhr.onreadystatechange = function() {
if (xhr.readyState == 4 && xhr.status === 200) {
console.log("responseURL -> ",xhr.responseURL)
}
}
}
3.4 status(只读) 和 statusText(只读)
status 返回一个无符号短整型(unsigned short)数字,代表请求的响应状态(也是http请求的响应状态码)。
返回一个 DOMString,其中包含 HTTP 服务器返回的响应状态。与 XMLHTTPRequest.status 不同的是,它包含完整的响应状态文本(例如,”200 OK”)。
测试:如下模拟了几种响应 status
后端代码:
package com.binghe.xmlhttprequestdemo.controller.available.attritube;
/**
* ResponseController
* 用于测试 XMLHttpRequest 响应状态和响应状态文字
* @author bing he
* @version 2020.10.13
*
*/
@RestController
@RequestMapping("status")
public class StatusAndStatusTextContrller {
/**
* status/200
*/
@RequestMapping("status/200")
public String status200(HttpServletRequest request, HttpServletResponse response) {
return "返回一个字符串";
}
/**
* status/405
*/
@PostMapping("status/405")
public void status405(HttpServletRequest request, HttpServletResponse response) {
}
/**
* status/500
*/
@RequestMapping("status/500")
public void status500(HttpServletRequest request, HttpServletResponse response) {
String null500 = null;
null500.charAt(0);
}
}
前端代码
var curModule = "status/";
bindFun();
function bindFun() {
$("#status-200").on("click", {
url : "status/200"
}, sendRequest);
$("#status-404").on("click", {
url : "status/404"
}, sendRequest);
$("#status-405").on("click", {
url : "status/405"
}, sendRequest);
$("#status-500").on("click", {
url : "status/500"
}, sendRequest);
}
/**
requestType: 请求方式
url:请求地址
*/
function sendRequest(event) {
var inurl = event.data.url;
var xhr = new XMLHttpRequest();
//console.log('0 UNSENT', xhr.statusText);
var url = $.rootPath + curModule + inurl;
var method = "GET";
xhr.open(method, url);
xhr.send(null);
xhr.onprogress = function() {
console.log("status为:",xhr.status);
console.log("statusText为:", xhr.statusText);
}
xhr.onload = function() {
console.log("status为:", xhr.status);
console.log("statusText为:",xhr.statusText);
}
}
输出结果:
注:输出结果只显示了405状态码的,其他输出类似,但是都没有statusText, 不同的浏览器返回的内容也不同,具体见:https://blog.csdn.net/weixin_30596735/article/details/94855793
据说是http 2.0不在返回 statusText,这个问题待学习http时再弄清楚。
3.5 timeout 和 ontimeout
虽然 ontimeout 属于 xhr 的实例的事件,但是此处放在与 timeout 一起测试,后续的事件的测试中不在测试次事件。
timeout 是一个无符号长整型数,代表着一个请求在被自动终止前所消耗的毫秒数。默认值为 0,意味着没有超时。超时并不应该用在一个 document environment 中的同步 XMLHttpRequests 请求中,否则将会抛出一个 InvalidAccessError 类型的错误。当超时发生, timeout 事件将会被触发。
以下通过设置 timeout 为1ms 来模拟请求超时。请求超时是会触发ontimeout事件。
测试:timeout 和 ontimeout
$("#timeout").on('click', function() {
var xhr = new XMLHttpRequest();
var url = $.rootPath + "timeout/timeout";
xhr.timeout = 1; //设置超时为1ms,模拟超时
xhr.ontimeout = function() { //监听超时事件
console.log("请求超时了")
}
xhr.open("GET", url)
xhr.send();
})
控制台输出
四、实例对象的可用方法
xhr可用的实例对象主要包括open()、setRequestHeader()、send()、getAllResponseHeaders()、getResponseHeader()、abort()、overrideMimeType()。
4.1 open()、setRequestHeader()、send()
以上三个方法都是在 xhr 对象创建之后和请求发送之前可调用的方法。调用顺序也和上面的顺序一样,但是 setRequestHeader 并不是发送请求必须调用的。下面就分别详情介绍三个方法的用法。
4.1.1 open()
open() 方法初始化一个请求。在创建xhr对象后可调用来初始化请求。
语法:
xhr.open(method, url);
xhr.open(method, url, async);
xhr.open(method, url, async, user);
xhr.open(method, url, async, user, password);
参数:
method | 要使用的HTTP方法,比如「GET」、「POST」、「PUT」、「DELETE」、等。对于非HTTP(S) URL被忽略。大小写都可以,混着写也没事,例如get, Get都能正常使用,建议都大写 |
---|---|
url | 一个DOMString 表示要向其发送请求的URL。 |
async(可选) | 一个可选的布尔参数,默认为true ,表示要不要异步执行操作。如果值为false ,send() 方法直到收到答复前不会返回。如果true ,已完成事务的通知可供事件监听器使用。如果multipart 属性为true 则这个必须为true ,否则将引发异常。 |
user(可选) | 可选的用户名用于认证用途,如果服务器需要验证;默认为null 。 |
password(可选) | 可选的密码用于认证用途,如果服务器需要验证; 默认为null 。 |
method 和 url 已经使用过,且是必须的参数,此处就测试一下 async 、user、password。(user、**password不知道是怎么使用的,暂时待测试)
async 的测试,以下是将async设置为 true 和 false 的测试结果。 async 为true 时,表示请求是异步执行的,即不会等到请求完成才去执行请求之后的代码。所以控制台先打印了 “异步请求发送之后的代码”,而后才打印了请求的结果。async 为true 时,表示请求是同步执行的,此时会阻塞浏览器 js 引擎的主线程,只有在请求结束之后才会执行请求之后的代码(使用同步是浏览器会提示:Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user’s experience)。此处可以简单的得出结论,不要轻易使用同步,可能导致页面的卡顿,影响用户体验。**
测试:open同步和异步的区别
代码:
$("#open-async-yes").on('click', function() {
var xhr = new XMLHttpRequest();
var url = $.rootPath + "method/launch";
xhr.open("GET", url, true); //将async设置成false,表示该请求是同步执行
xhr.onload = function() {
console.log("异步请求后台返回的结果:",xhr.responseText)
}
xhr.send();
console.log("异步请求发送之后的代码")
})
$("#open-async-false").on('click', function() {
var xhr = new XMLHttpRequest();
var url = $.rootPath + "method/launch";
xhr.open("GET", url, false); //将async设置成false,表示该请求是同步执行
xhr.onload = function() {
console.log("同步请求后台返回的结果:", xhr.responseText)
}
xhr.send();
console.log("同步请求发送之后的代码")
})
4.1.2 setRequestHeader()
setRequestHeader() 是设置HTTP请求头部的方法。此方法必须在 open() 方法和 send() 之间调用。可以用于设置http协议的头部信息,也可以设置自定义的头部信息。
语法:
xhr.setRequestHeader(header, value);
参数:
header | 请求头的名字 |
---|---|
value | 请求头的值 |
测试1:设置http协议提供请求头
如下测试设置http的请求头,未设置 Accept-Language 时,默认值是zh-CN,将Accept-Language 设置为 en-US,en;q=0.5。查看浏览器开发工具可以看到设置已经生效。
默认:
设置Accept-Language 设置为 en-US,en;q=0.5
$("#set-request-header").on("click", function() {
var xhr = new XMLHttpRequest();
var url = $.rootPath + "method/launch";
xhr.open("GET", url);
xhr.setRequestHeader("Accept-Language", "en-US,en;q=0.5"); //设置语言
xhr.onload = function() {
console.log("同步请求后台返回的结果:", xhr.responseText)
}
xhr.send();
})
测试2:自定义请求头
可以自定义请求后,在 java 后台使用 getHeader(headerName) 可以获取自定义请求头的值。
$("#set-custom-request-header").on("click", function() {
var xhr = new XMLHttpRequest();
var url = $.rootPath + "method/launch";
xhr.open("GET", url);
xhr.setRequestHeader("Custom-Header", "test"); //自定义请求头
xhr.onload = function() {
console.log("同步请求后台返回的结果:", xhr.responseText)
}
xhr.send();
})
后台:
@RequestMapping("launch")
public String launch(HttpServletRequest request, HttpServletResponse XMLHttpRequest) {
String customHeader = request.getHeader("Custom-Header");
System.err.println(customHeader);
return "这是MethodController的launch方法";
}
4.1.3 send()
send() 方法用于发送 HTTP 请求。如果是异步请求(默认为异步请求),则此方法会在请求发送后立即返回;如果是同步请求,则此方法直到响应到达后才会返回。XMLHttpRequest.send() 方法接受一个可选的参数,其作为请求主体;如果请求方法是 GET 或者 HEAD,则应将请求主体设置为 null。
Note: 请注意不要使用一个简单的AarryBuffer对象作为参数,ArrayBuffer已经不再是ajax规范的一部分,请改用ArrayBufferView
语法:
xhr.send(body)
参数:
body(可选) | - null - FormData对象FormData对象 - Document对象 在这种情况下,它在发送之前被序列化 - Blob对象 - ArrayBufferView对象 - DOMString |
---|---|
测试1:DOMString
DOMString的方式传数据,需要设置正确的请求头 application/x-www-form-urlencoded
前端代码:
$("#send-dom-string").on("click", function() {
var xhr = new XMLHttpRequest();
var url = $.rootPath + "method/send/dom/string";
xhr.open("POST", url);
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");//需要设置请求同
xhr.onload = function() {
console.log("send/dom/string的结果:", xhr.responseText)
}
xhr.send("name=domstring&age=xxx");
})
后端代码:
@RequestMapping("send/dom/string")
public String sendDOMString(HttpServletRequest request, HttpServletResponse XMLHttpRequest) {
String name = request.getParameter("name");
String age = request.getParameter("age");
return "后台收到的数据为:" + name + "," + age;
}
控制台打印:
测试2:FormData对象上传参数
FormData 接口提供了一种表示表单数据的键值对 key/value 的构造方式,并且可以轻松的将数据通过XMLHttpRequest.send() 方法发送出去,本接口和此方法都相当简单直接。如果送出时的编码类型被设为 “multipart/form-data”,它会使用和表单一样的格式。
前端代码:
$("#send-form-data").on("click", function() {
var xhr = new XMLHttpRequest();
var url = $.rootPath + "method/send/form/data";
xhr.open("POST", url); //注意:不能使用GET请求,GET请求是body应该设置为null
xhr.onload = function() {
console.log("send/form/data的结果:", xhr.responseText)
}
var formData = new FormData(); //创建一个FormData对象
formData.append("name", "张三"); //在对象中添加 键值对k/v name/张三
formData.append("age", "18");
xhr.send(formData); //发出请求
})
后端代码:后端直接使用request.getParameter(String name)方法获取 send 提交的数据
/**
* 测试 XMLHttpRequest send方法,body的内容为FormData
* @param request
* @param response
*/
@RequestMapping("send/form/data")
public String sendFormData(HttpServletRequest request, HttpServletResponse XMLHttpRequest) {
String name = request.getParameter("name");
String age = request.getParameter("age");
return "后台收到的数据为:" + name + "," + age;
}
测试3:formData上传文件
ajax可以利用 type 为 file 的 input 来实现文件的上传。前端使用FormData,后端使用 MultipartFile 来接收文件。
前端代码:
$("#send-form-data-upload").on("click", function() {
var xhr = new XMLHttpRequest();
var url = $.rootPath + "method/send/form/data/upload";
var formData = new FormData();
var file = $("#upload-file")[0].files[0];
xhr.open("POST", url);
xhr.onload = function() {
console.log("send/form/data/upload的结果:", xhr.responseText)
}
xhr.upload.onprogress = function(event) { //监听上传的事件,才控制带打印出上传的进度
var loaded = event.loaded;
var total = event.total;
var percent = (loaded/total)*100
console.log(percent.toFixed(2), "%")
}
console.log(file)
formData.append("file", file); //第一个参数是后台读取的请求key值
formData.append("fileName", file.name);
xhr.send(formData);
})
后端代码:
private String tempPath = "E:\\project\\BackEnd\\xmlhttprequest-demo\\src\\main\\resources\\static\\upload";
/**
* 测试 XMLHttpRequest send方法,body的内容为FormData 上传文件
* @param request
* @param response
* @throws FileUploadException
* @throws IOException
*/
@RequestMapping("send/form/data/upload")
public String sendFormDataUpload(HttpServletRequest request,@RequestParam("file") MultipartFile file, HttpServletResponse response) {
OutputStream os = null;
InputStream inputStream = null;
String fileName = request.getParameter("fileName");
System.err.println(fileName);
try {
inputStream = file.getInputStream();
} catch (IOException e) {
e.printStackTrace();
}
try {
byte[] bs = new byte[1024];
// 读取到的数据长度
int len;
// 输出的文件流保存到本地文件
File tempFile = new File(tempPath);
if (!tempFile.exists()) {
tempFile.mkdirs();
}
os = new FileOutputStream(tempFile.getPath()+ "/" + File.separator + fileName);
// 开始读取
while ((len = inputStream.read(bs)) != -1) {
os.write(bs, 0, len);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
// 完毕,关闭所有链接
try {
os.close();
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return "文件上传成功";
}
控制台打印结果:
注:spring默认的上传文件限制是1M,需要配置最大请求内容和最大的文件大小。在yml文件中的配置如下:
server:
port: 8080
tomcat:
max-swallow-size: 104857600
spring:
servlet:
multipart:
max-file-size: 104857600
max-request-size: 104857600
file-size-threshold: 10485760
测试4:Document
Document 的方式在body中传数据。后台需要使用流来接收文件。
前端代码:
$("#send-document").on("click", function() {
var xhr = new XMLHttpRequest();
var url = $.rootPath + "method/send/document";
xhr.open("POST", url);
xhr.setRequestHeader("",)
xhr.onload = function() {
console.log("send/document的结果:", xhr.responseText)
}
//新建一个文档
var doc = new Document();
var personNode = doc.createElement("person");
var name = doc.createElement("name");
var nameValue = doc.createTextNode("张三");
name.appendChild(nameValue);
var age = doc.createElement("age");
var ageValue = doc.createTextNode("18");
age.appendChild(ageValue);
personNode.appendChild(name);
personNode.appendChild(age);
doc.append(personNode);
xhr.send(doc);
})
后端代码:
/**
* 测试 XMLHttpRequest send方法,body的内容为document
* @param request
* @param response
*/
@RequestMapping("send/document")
public String sendDocument(HttpServletRequest request, HttpServletResponse XMLHttpRequest) {
ServletInputStream in = null;
try {
byte[] doc = new byte[1024];
in = request.getInputStream();
in.read(doc);
String aa = new String(doc);
System.err.println("啥也没有:" + aa);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return "后台收到数据";
}
后台输出数据为:
测试5:Blob
Blob对象表示一个不可变、原始数据的类文件对象。它的数据可以按文本或二进制的格式进行读取,也可以转换成 ReadableStream 来用于数据操作。其具体的介绍见:TODO
前端可以用 js 对象来生成 Blob 对象,并直接将 Blob对象发送到后端。后端通过 request.getInputStream() 获取输入流读取请求体重的文件内容。
前端代码:
//使用blob的方式上传文件
$("#send-blob").on("click", function() {
var json = { hello: "world" };
var blob = new Blob([JSON.stringify(json, null, 2)], { type: 'application/json' });
var url = $.rootPath + "method/send/blob";
var xhr = new XMLHttpRequest();
xhr.open("POST", url);
xhr.onload = function() {
console.log("同步请求后台返回的结果:", xhr.responseText)
}
xhr.send(blob);
})
后端代码:
@RequestMapping("send/blob")
public String sendBlob(HttpServletRequest request, HttpServletResponse response) {
String fileName = "blobCreate.json";
OutputStream os = null;
InputStream inputStream = null;
try {
inputStream = request.getInputStream(); //从请求中获取输入流
// 输出的文件流保存到本地文件
File tempFile = new File(tempPath);
if (!tempFile.exists()) {
tempFile.mkdirs();
}
os = new FileOutputStream(tempFile.getPath()+ "/" + File.separator + fileName);//创建文件输出流
byte[] bs = new byte[1024];
// 读取到的数据长度
int len;
// 开始读取
while ((len = inputStream.read(bs)) != -1) {
os.write(bs, 0, len);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
// 完毕,关闭所有链接
try {
os.close();
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return "文件上传成功";
}
测试6:arrayBufferView
4.2 getAllResponseHeaders()、getResponseHeader()
4.2.1 getResponseHeader()
返回包含指定响应头的字符串,如果响应尚未收到或响应中不存在该报头,则返回 null。
语法:
var header = xhr.getResponseHeader(name);
参数:
name | 一个字符串,表示要返回的报文项名称。 |
---|---|
返回值:
报文项值,如果连接未完成,响应中不存在报文项,或者被W3C限制,则返回null。
测试1:获取请求头
前端代码:
$("#get-response-header").on("click", function() {
var xhr = new XMLHttpRequest();
var url = $.rootPath + "method/get/response/header";
xhr.open("POST", url);
xhr.onload = function() {
var contentType = xhr.getResponseHeader("Content-Type");
var customHeader = xhr.getResponseHeader("Custom-Header");
console.log("Content-Type:" + contentType)
console.log("Custom-Header:" + customHeader)
}
xhr.send();
})
后端代码:
@RequestMapping("get/response/header")
public String getResponseHeader(HttpServletRequest request, HttpServletResponse response) {
response.setHeader("Custom-Header", "test-header");;
return "getResponseHeader方法";
}
4.2.2 getAllResponseHeaders()
getAllResponseHeaders() 方法返回所有的响应头,以 CRLF 分割的字符串,或者 null 如果没有收到任何响应。 注意: 对于复合请求 ( multipart requests ),这个方法返回当前请求的头部,而不是最初的请求的头部。
语法:
var headers = xhr.getAllResponseHeaders();
返回值:
返回当前请求所有的请求头。以 CRLF 分割的字符串,即后面都有回车换行符 ‘\r\n’
测试:获取所有请求头
前端代码:
$("#get-all-response-headers").on("click", function() {
var xhr = new XMLHttpRequest();
var url = $.rootPath + "method/get/response/header";
xhr.open("POST", url);
xhr.onload = function() {
var allHeaders = xhr.getAllResponseHeaders();
console.log("allHeaders:\n" + allHeaders)
}
xhr.send();
})
4.3 abort方法 和 onabort事件
如果该请求已被发出,xhr.abort() 方法将终止该请求。当一个请求被终止,它的 readyState 将被置为 XMLHttpRequest.UNSENT (0),并且请求的 status 置为 0。
当调用abort终止请求后,会触发 onabort 事件。
测试:abort 方法和 onabort 事件
前端代码:
$("#abort").on("click", function() {
var xhr = new XMLHttpRequest();
var url = $.rootPath + "method/abort";
xhr.open("POST", url);
xhr.onabort = function() {
console.log("请求被终止了");
console.log("readyState:" + xhr.readyState)
}
xhr.send();
xhr.abort();
console.log("abort之后的readyState:" + xhr.readyState)
})
4.4 overrideMimeType() - 实在没搞懂
overrideMimeType 方法是指定一个MIME类型用于替代服务器指定的类型,使服务端响应信息中传输的数据按照该指定MIME类型处理。例如强制使流方式处理为”text/xml”类型处理时会被使用到,即使服务器在响应头中并没有这样指定。此方法必须在send方法之前调用方为有效。
语法:
xhr.overrideMimeType(mimeType)
参数:
mimeType | 一个 DOMString 指定具体的MIME类型去代替有服务器指定的MIME类型. 如果服务器没有指定类型,那么 XMLHttpRequest 将会默认为 "text/xml" . |
---|---|
五、实例对象的事件
5.1 onabort、onerror
onabort 事件会在XMLHttpRequest 请求操作被诸如 XMLHttpRequest.abort() 函数中止时调用。测试建 abort方法的测试
onerror 是XMLHttpRequest 事务由于错误而失败时调用的函数。例如连不上服务器
测试:onerror 关闭服务器
跳转到当前测试页面后,关闭服务器。点击onerror的按钮,此时由于服务器关闭,请求会出错,然后出发 onerror 事件。
前端代码:
$("#onerror").on('click', function() {
var xhr = new XMLHttpRequest();
var url = $.rootPath + "event/onerror";
xhr.open("POST", url);
xhr.onerror = function() {
console.log("出现错误了")
}
xhr.send();
})
5.2 onloadstart、onprogress、onload、onloadend
onloadstart 在XMLHttpRequest 开始传送数据时被调用
onprogress 是在 XMLHttpRequest 完成之前周期性调用的函数。
onload 当一个XMLHttpRequest请求完成的时候会触发load 事件,abort 或 error 是不会触发onload 的。
onloadend 当请求结束时触发, 无论请求成功 ( load) 还是失败 (abort 或 error)。
测试:正常情况下,onloadstart、onprogress、onload、onloadend是按顺序触发的。
前端代码:
$("#process").on('click', function() {
var xhr = new XMLHttpRequest();
var url = $.rootPath + "event/process";
xhr.open("POST", url);
xhr.onloadstart = function() {
console.log("onloadstart事件被触发")
}
xhr.onprogress = function() {
console.log("onprogress事件被触发")
}
xhr.onload = function() {
console.log("onload事件被触发")
}
xhr.onloadend = function() {
console.log("onloadend事件被触发")
}
xhr.send();
})
5.3 ontimeout
当进度由于预定时间到期而终止时,会触发timeout 事件。其测试见 3.5节 属性 timeout部分。