这次介绍使用XMLHttpRequest对象过程中,经常遇到三个问题的解决方法:
(在Ajax学习系列2—核心对象XMLHttpRequest中介绍了XMLHttpRequest对象的五步使用法)
AjaxCache.html
<!DOCTYPE html>
<html>
<head>
<title>ajax-测试缓存</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
</head>
<body>
<input type="button" value="测试缓存问题" onclick="checkCache()"/>
<div id="cacheMes"></div>
<script type="text/javascript">
var xmlhttp;
function checkCache(){
// 1.创建XMLHttpRequest对象
if(window.XMLHttpRequest){
// IE7,IE8,FireFox,Mozillar,Safari,Opera
xmlhttp = new XMLHttpRequest();
// 由于Mozillar版本的,XML以MimeType开头时,服务端可能会无法工作
if(xmlhttp.overrideMimeType){
xmlhttp.overrideMimeType("text/xml");
}
}else if(window.ActiveXObject){
// // IE5,IE5.5,IE6
var activexName = ["MSXML2.XMLHTTP","Miscrosoft.XMLHTTP"];
for(var i = 0;i < activexName.length;i++){
// 循环测试
try{
xmlhttp = new ActiveXObject(activeName[i]);
break;
}catch(e){};
}
}else{
alert("不能建立XMLHttpRequest对象");
return false;
}
// 2.注册回调方法
xmlhttp.onreadystatechange = callback; // 需要方法名
/*
// 为了屏蔽浏览器缓存,url中增加时间戳
var url = "Cache";
if(url.indexOf("?") > 0){
url = url + "&t=" + (new Date()).valueOf();
}else{
url = url + "?t=" + (new Date()).valueOf();
}
*/
// 3.设置和服务端交互的基本信息(GET方式)
xmlhttp.open("GET",url,true);
// 4.设置向服务端发送的数据,启动和服务端的交互
xmlhttp.send(null);
}
function callback(){
// alert(xmlhttp.readyState);
// 5.判断和服务端的交互是否完成,服务端是否正确返回数据,如果都正确,更新页面
if(xmlhttp.readyState ==4){
// 表示交互已完成
if(xmlhttp.status ==200){
// 表示服务器的相应代码是200,正确返回数据
//
// 纯文本数据的接受方法
var messageNode = document.getElementById("cacheMes");
messageNode.innerHTML = xmlhttp.responseText;
// xml数据对应的dom对象接受方法
// 使用的前提是,服务端需要设置content-type为text/xml
// var domXml = xmlhttp.responseXML;
}
}
}
</script>
</body>
</html>
Cache.java
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
*
* @author TCH
*/
public class Cache extends HttpServlet {
/**
* Processes requests for both HTTP
* <code>GET</code> and
* <code>POST</code> methods.
*
* @param request servlet request
* @param response servlet response
* @throws ServletException if a servlet-specific error occurs
* @throws IOException if an I/O error occurs
*/
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
try {
Integer counter = (Integer)request.getSession().getAttribute("counter");
if(null == counter){
counter = 0;
}else{
counter ++;
}
request.getSession().setAttribute("counter", counter);
out.println("当前计数器的值为:" + counter);
} finally {
out.close();
}
}
/**
* Handles the HTTP
* <code>GET</code> method.
*
* @param request servlet request
* @param response servlet response
* @throws ServletException if a servlet-specific error occurs
* @throws IOException if an I/O error occurs
*/
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
/**
* Handles the HTTP
* <code>POST</code> method.
*
* @param request servlet request
* @param response servlet response
* @throws ServletException if a servlet-specific error occurs
* @throws IOException if an I/O error occurs
*/
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
/**
* Returns a short description of the servlet.
*
* @return a String containing servlet description
*/
@Override
public String getServletInfo() {
return "Short description";
}// </editor-fold>
}
单击按钮多次,发现结果依然是0,达不到我们想要的结果。原因是当第二次单击按钮时,给服务端发送的和第一次发送的是相同的url,服务端回到相应的Session中查看,如果有之前访问的结果,则直接从缓存中提取数据。利用HttpWatch工具证明这点:
Result列:200表示从服务端成功返回;(Cache)表示结果从缓存中返回的
URL列:两个地址相同。
屏蔽缓存
思想:善意的欺骗—让浏览器看到每次的url都不一样,也就不会到缓存中去找了。
通过url中增加时间戳实现
// 为了屏蔽浏览器缓存,url中增加时间戳
var url = "Cache";
if(url.indexOf("?") > 0){
url = url + "&t=" + (new Date()).valueOf();
}else{
url = url + "?t=" + (new Date()).valueOf();
}
这次再次点击按钮,就达到了我们想要看到的效果
利用HttpWatch工具证明这点:
解决中文乱码问题
解决跨域访问问题
因为使用Ajax的跨域访问,会带来不安全因素。
解决:通过同域的代理,访问跨域的服务器
用户名校验实例:
AjaxProxy.html
<!--
To change this template, choose Tools | Templates
and open the template in the editor.
-->
<!DOCTYPE html>
<html>
<head>
<title></title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
</head>
<body>
<input type="text" id="userName"/>
<input type="button" name="submit" onclick="submit()" value="AJAX校验"/>
<div id="message"></div>
<script type="text/javascript">
var xmlhttp;
function submit(){
// 1.创建XMLHttpRequest对象
if(window.XMLHttpRequest){
// IE7,IE8,FireFox,Mozillar,Safari,Opera
xmlhttp = new XMLHttpRequest();
// 由于Mozillar版本的,XML以MimeType开头时,服务端可能会无法工作
if(xmlhttp.overrideMimeType){
xmlhttp.overrideMimeType("text/xml");
}
}else if(window.ActiveXObject){
// IE5,IE5.5,IE6
var activexName = ["MSXML2.XMLHTTP","Miscrosoft.XMLHTTP"];
for(var i = 0;i < activexName.length;i++){
try{
xmlhttp = new ActiveXObject(activeName[i]);
break;
}catch(e){};
}
}else{
alert("不能建立XMLHttpRequest对象");
return false;
}
// 2.注册回调方法
xmlhttp.onreadystatechange = callback; // 需要方法名
var name = document.getElementById("userName").value;
// 两次编码,屏蔽请求数据中包含中文,服务端接受错误导致中文乱码问题
name = encodeURI(encodeURI(name));
// 通过代理解决跨域问题
var url = "http://192.168.24.145:8084/VerifyUserName/AjaxServer?name=" + name;
if(url.indexOf("http://") > 0){
// url = "http://192.168.24.151:8080/Ajax/AjaxServer?name="+name
url.replace("?","&");
// url = "http://192.168.24.151:8080/Ajax/AjaxServer&name="+name
url = "Proxy?url" + url;
// url = "Proxy?http://192.168.24.151:8080/Ajax/AjaxServer&name="+name
}
// 3.设置和服务端交互的相应参数(GET方式)
xmlhttp.open("GET",url,true);
// 4.设置向服务端发送的数据,启动和服务端的交互
xmlhttp.send(null);
}
function callback(){
// alert(xmlhttp.readyState);
// 5.判断和服务端的交互是否完成,服务端是否正确返回数据,如果都正确,更新页面
if(xmlhttp.readyState ==4){
// 表示交互已完成
if(xmlhttp.status ==200){
// 表示服务器的相应代码是200,正确返回数据
//
// 纯文本数据的接受方法
var messageNode = document.getElementById("message");
messageNode.innerHTML = xmlhttp.responseText;
// xml数据对应的dom对象接受方法
// 使用的前提是,服务端需要设置content-type为text/xml
// var domXml = xmlhttp.responseXML;
}
}
}
</script>
</body>
</html>
Proxy.java
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.OutputStreamWriter;
import java.net.*;
import java.util.Enumeration;
/**
*
* @author TCH
*/
public class Proxy extends HttpServlet {
/**
* Processes requests for both HTTP
* <code>GET</code> and
* <code>POST</code> methods.
*
* @param request servlet request
* @param response servlet response
* @throws ServletException if a servlet-specific error occurs
* @throws IOException if an I/O error occurs
*/
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
try {
} finally {
out.close();
}
}
/**
* Handles the HTTP
* <code>GET</code> method.
*
* @param request servlet request
* @param response servlet response
* @throws ServletException if a servlet-specific error occurs
* @throws IOException if an I/O error occurs
*/
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
StringBuffer url = new StringBuffer();
url.append(request.getParameter("url"));
Enumeration enu = request.getParameterNames();
int total = 0;
while (enu.hasMoreElements()) {
String name = (String) enu.nextElement();
if (!name.equals("url")) {
if (total == 0) {
url.append("?").append(name).append("=").append(URLEncoder.encode(request.getParameter(name), "UTF-8"));
} else {
url.append("&").append(name).append("=").append(URLEncoder.encode(request.getParameter(name), "UTF-8"));
}
total++;
}
}
PrintWriter out = response.getWriter();
if (url != null) {
URL connect = new URL(url.toString());
BufferedReader reader = new BufferedReader(new InputStreamReader(connect.openStream(), "GB2312"));
String line;
while ((line = reader.readLine()) != null) {
out.println(line);
}
reader.close();
}
}
/**
* Handles the HTTP
* <code>POST</code> method.
*
* @param request servlet request
* @param response servlet response
* @throws ServletException if a servlet-specific error occurs
* @throws IOException if an I/O error occurs
*/
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
String url = request.getParameter("url");
StringBuffer param = new StringBuffer();
Enumeration enu = request.getParameterNames();
int total = 0;
while (enu.hasMoreElements()) {
String name = (String) enu.nextElement();
if (!name.equals("url")) {
if (total == 0) {
param.append(name).append("=").append(URLEncoder.encode(request.getParameter(name), "UTF-8"));
} else {
param.append("&").append(name).append("=").append(URLEncoder.encode(request.getParameter(name), "UTF-8"));
}
total++;
}
}
PrintWriter out = response.getWriter();
if (url != null) {
URL connect = new URL(url.toString());
URLConnection connection = connect.openConnection();
connection.setDoOutput(true);
OutputStreamWriter paramout = new OutputStreamWriter(connection.getOutputStream());
paramout.write(param.toString());
paramout.flush();
BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream(), "GB2312"));
String line;
while ((line = reader.readLine()) != null) {
out.println(line);
}
paramout.close();
reader.close();
}
}
/**
* Returns a short description of the servlet.
*
* @return a String containing servlet description
*/
@Override
public String getServletInfo() {
return "Short description";
}// </editor-fold>
}
AjaxServer.java(远程服务端)
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
*
* @author TCH
*/
public class AjaxServer extends HttpServlet {
/**
* Processes requests for both HTTP
* <code>GET</code> and
* <code>POST</code> methods.
*
* @param request servlet request
* @param response servlet response
* @throws ServletException if a servlet-specific error occurs
* @throws IOException if an I/O error occurs
*/
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
try {
String old = request.getParameter("name");
if (old == null || old.length() == 0) {
out.println("用户名不能为空");
} else {
String name = new String(old.getBytes("ISO8859-1"), "gb2312");
if (name.equals("tch")) {
//4。和传统应用不同之处。这一步需要将用户感兴趣的数据返回给页面段,而不是将一个新的页面发送给用户
//写法没有变化,本质发生了改变
out.println("用户名[" + name + "]已经存在,请使用其他用户名");
} else {
out.println("用户名[" + name + "]尚未存在,可以使用该用户名注册");
}
}
} finally {
out.close();
}
}
/**
* Handles the HTTP
* <code>GET</code> method.
*
* @param request servlet request
* @param response servlet response
* @throws ServletException if a servlet-specific error occurs
* @throws IOException if an I/O error occurs
*/
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
/**
* Handles the HTTP
* <code>POST</code> method.
*
* @param request servlet request
* @param response servlet response
* @throws ServletException if a servlet-specific error occurs
* @throws IOException if an I/O error occurs
*/
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
/**
* Returns a short description of the servlet.
*
* @return a String containing servlet description
*/
@Override
public String getServletInfo() {
return "Short description";
}// </editor-fold>
}
小结