微軟最早以ActiveX對象的形式在IE5中引入了XMLHttpRequest對象,經Google發揚光大之后,目前所有的瀏覽器都已經支持XMLHttpRequest了,目前W3C正在制定XMLHttpRequest Level 2標准草案,相對於原來的XMLHttpRequest,新標准的XMLHttpRequest有了很大的改進,提供了很多新的功能。
本文就新舊XMLHttpRequest對象進行一個簡單的比較,並介紹新標准的XMLHttpRequest對象的改進之處。
原來的XMLHttpRequest對象的缺點:
1.只支持文本數據的傳遞,不支持二進制數據。
2.傳遞數據的時候,沒有progress事件,不能實時顯示傳遞的進度信息。
3.受同源策略的限制,不能發送跨域的請求。
新標准的XMLHttpRequest的改進:
1.可以傳遞二進制數據。
2.在服務器端設置了CORS允許跨域請求的時候,可以獲取跨域的數據。
3.可以使用原生的FormData對象來管理要發送的表單數據。
4.提供了progress事件,可以提供進度信息。在下載和上傳的時候,都有progress事件,下載的時候,progress事件由XMLHttpRequest本身觸發,上傳的時候,由XMLHttpRequest.upload對象觸發,可以通過addEventListener來添加事件處理方法。
利用新標准的XMLHttpRequest對象,我們可以非常方便的實現文件AJAX上傳功能。
HTML:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>使用XMLHttpRequest上傳文件</title>
<style type="text/css">
.container {
width: 500px;
margin: 0 auto;
}
.progress-bar {
border: 1px solid #000;
}
.progress {
width: 0;
background: #DEDEDE;
height: 20px;
}
</style>
</head>
<body>
<div class="container">
<p>
選擇文件:
<input type="file" id="ipt-file"/>
<button type="button" id="btn-upload">上傳</button>
</p>
<div class="progress-bar">
<div class="progress" id="progress"></div>
</div>
<p id="info"></p>
</div>
<script src="./js/upload.js"></script>
</body>
</html>
JavaScript:
upload.js的具體代碼如下:
var button = document.querySelector("#btn-upload"),
input = document.querySelector("#ipt-file"),
progress = document.querySelector("#progress"),
info = document.querySelector("#info");
var upload = function() {
if (input.files.length === 0) {
console.log("未選擇文件");
return;
}
var formData = new FormData();
formData.append("file", input.files[0]);
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readyState === 4 && xhr.status === 200) {
console.log(xhr.responseText);
info.innerHTML = xhr.responseText;
}
};
xhr.upload.addEventListener("progress", function(event) {
if(event.lengthComputable){
progress.style.width = Math.ceil(event.loaded * 100 / event.total) + "%";
}
}, false);
xhr.open("POST", "./upload");
xhr.send(formData);
};
button.addEventListener("click", upload, false);
Java:
上傳服務端采用Servlet來實現。
package com.servlet;
import java.io.File;
import java.io.PrintWriter;
import java.util.Iterator;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
@WebServlet(description = "文件上傳", urlPatterns = { "/upload" })
public class UploadServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
private String filePath;
private int maxFileSize = 1024 * 1024;
public void init() {
filePath = this.getServletContext().getRealPath("/") + File.separator
+ "upload";
File file = new File(filePath);
if (!file.exists()) {
file.mkdirs();
}
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, java.io.IOException {
response.setContentType("text/plain");
response.setCharacterEncoding("utf-8");
PrintWriter out = response.getWriter();
DiskFileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload upload = new ServletFileUpload(factory);
upload.setSizeMax(maxFileSize);
try {
List fileItems = upload.parseRequest(request);
Iterator i = fileItems.iterator();
while (i.hasNext()) {
FileItem fi = (FileItem) i.next();
if (!fi.isFormField()) {
String fileName = fi.getName();
File file = new File(filePath + File.separator + fileName);
fi.write(file);
out.println(fileName + "上傳成功");
}
}
} catch (Exception ex) {
out.println("上傳文件失敗:" + ex.getMessage());
} finally {
out.close();
}
}
}
