最近遇到一个项目,你的JSP网页和服务器提供的服务不在一个域中,但是需要通过AJAX方式来跨域调用服务器的服务,例如
你的JSP页面:http://192.168.6.26:7001/First_Web/TestXML.jsp
服务器的服务地址:http://10.8.2.60:9082/PGIS_S_Map/XMLPort
众所周知,AJAX是不能跨域的,因为跨域访问会涉及很严重的安全问题,不仅是AJAX技术,采用任何方式(例如表单post)来跨域访问都会涉及严重的问题。例如你在你的网站中通过AJAX去跨域修改网站B后台服务器的数据,这里面当然会涉及到权限问题,如果权限被绕过(例如通过CSRF,XSS等技术窃取网站B的cookies),跨域访问又被允许的情况下,网站B的后台数据就会被窃取和破坏。
目前AJAX跨域解决方式主要有以下几种:
一、主域名相同,子域名不同
例如:http://www.aa.com/和book.aa.com,主域名都是aa.com,
解决方式:此时可以通过设置document.domain方式解决,具体可以参考http://blog.sina.com.cn/s/blog_62449fcf0100p3bp.html
二、域名完全不同
例如我在项目中遇到的就是这种情况,这种情况又可以分为两类:
1)客户端只需要通过get方式来跨域请求服务端的服务
解决方式:jQuery+jsonp
具体可参考:http://www.biaodianfu.com/json-jsonp.html
2)客户端需要通过POST和GET方式来跨域请求服务端的服务
解决方式:中转代理方式,客户端在本地建立一个Servlet和JSP做中转代理,先将请求发送到代理,代理将请求转发到服务器,并接收反馈结果,并将结果返回到客户端
下面介绍代理方式:
1)客户端TestXML.jsp,其中txtInput用于输入请求的xml数据,txtOutput用于输出返回的XML数据,客户端将请求的XML数据和服务器的服务地址一致发送给代理ClientServlet
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>test XML</title>
<SCRIPT LANGUAGE="JavaScript">
var XMLHttpReq;
//创建XMLHttpRequest对象,通过XMLHttpRequest请求服务器端的数据
function createXMLHttpRequest() {
if(window.XMLHttpRequest) { //Mozilla 浏览器
XMLHttpReq = new XMLHttpRequest();
}
else if (window.ActiveXObject) { // IE浏览器
try {
XMLHttpReq = new ActiveXObject("Msxml2.XMLHTTP");
}catch (e) {
try {
XMLHttpReq = new ActiveXObject("Microsoft.XMLHTTP");
} catch (e) {}
}
}
}
//发送请求函数到服务器,这里服务器的处理程序为servlet程序
function sendRequest()
{
document.getElementById("txtOutput").innerHTML ="正在查询,请您稍等......";
createXMLHttpRequest();
var xmldata = "xml="+document.getElementById("txtInput").value;
var urldata = "url=http://10.8.2.60:9082/PGIS_S_Map/XMLPort";
var url = "Client";
var param = xmldata+"&"+ urldata;
XMLHttpReq.open("post",url,true);
XMLHttpReq.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
XMLHttpReq.onreadyStatechange= XMLHttpReq.onreadystatechange = processResponse;
XMLHttpReq.send(param);
}
//处理服务器端返回的信息函数
function processResponse() {
if (XMLHttpReq.readyState == 4) { // 判断对象状态
if (XMLHttpReq.status == 200) { // 信息已经成功返回,开始处理信息
Display();
} else { //页面不正常
window.alert("您所请求的页面有异常。");
}
}
}
//网页局部刷新,显示服务器端返回的数据
function Display() {
var msg=XMLHttpReq.responseText;
document.getElementById('txtOutput').value=msg;
}
</SCRIPT>
</head>
<body>
<TEXTAREA ID=txtInput rows=15 style="width: 100%"></TEXTAREA>
<input type="button" value="显示结果!" onClick="sendRequest();">
<TEXTAREA ID=txtOutput rows=15 style="width: 100%"></TEXTAREA>
</body>
</html>
2)服务器端ClientServlet,解析服务器传送过来的xml数据和服务地址,并将xml数据转发到该服务地址
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class ClientServlet extends HttpServlet {
public void init(ServletConfig config) throws ServletException {
super.init();
}
public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
{
}
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
try
{
//获取需要提交的xml数据和转发的url地址
String urldata = new String(request.getParameter("url").getBytes("iso-8859-1"), "utf-8");
String xmldata = new String(request.getParameter("xml").getBytes("iso-8859-1"), "utf-8");
//设置url连接
URL url = new URL(urldata);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("POST"); // 提交模式
//conn.setConnectTimeout(10000);//连接超时 单位毫秒
conn.setReadTimeout(9000);//读取超时 单位毫秒 这一部分可以相对设大一点 避免时间过短 数据传送不回来 出现java.net.SocketTimeoutException: Read timed out错误
conn.setDoOutput(true);// 是否输入参数
//提交xml数据到该url
StringBuffer params = new StringBuffer();
// 表单参数与get形式一样
params.append("xml").append("=").append(xmldata);
byte[] bypes = params.toString().getBytes();
conn.getOutputStream().write(bypes);// 输入参数
//获取从该url反馈回来的数据,并将该数据返回到ajax客户端
BufferedInputStream in = new BufferedInputStream(conn.getInputStream());
byte[] bs = new byte[1024];
int startpos = 0;
int num = 0;
num = in.read(bs, startpos, 1024);
OutputStream out = response.getOutputStream();
while (num != -1) {
out.write(bs, 0, num);
num = in.read(bs, 0, 1024);
}
//释放内存
out.flush();
out.close();
in.close();
conn.disconnect();
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
3)服务器web.xml配置
<web-app version="2.4"
xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<servlet>
<servlet-name>ClientServlet</servlet-name>
<servlet-class>Sql.ClientServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ClientServlet</servlet-name>
<url-pattern>/Client</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>
此外,AJAX跨域还有其他几种方式,具体可以参见
http://www.cnblogs.com/rainman/archive/2011/02/20/1959325.html
http://zhaohe162.blog.163.com/blog/static/3821679720113219250547/
http://www.blogjava.net/itspy/archive/2007/02/11/99262.html