最近接手一個項目,新項目需要調用老項目的接口,但是老項目和新項目不再同一個域名下,所以必須進行跨域調用了,但是老項目又不能進行任何修改,所以jsonp也無法解決了,於是想到了使用了Httpclient來進行服務端的“跨域”來替代jsonp的客戶端跨域方案。
上一篇博文中,詳細剖析了jsonp的跨域原理,本文使用Httpclient來替代jsonp的客戶端跨域方案。
先去 http://hc.apache.org/downloads.cgi 下載最新版httpclient。解壓tutorial文件夾中有html和PDF的使用介紹。
下面實現從8888端口的html4項目中跨域訪問8080端口的html5項目中的JsonServlet:
1)在html4中建立一個中間代理servelt和一個工具類,工具類代碼如下:
import java.io.IOException;
import java.io.OutputStream;
import org.apache.http.HttpEntity;
import org.apache.http.StatusLine;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpResponseException;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
public class HttpUtil
{
public static boolean returnResponseOfUrl(String url, OutputStream os)
{
CloseableHttpClient httpclient = HttpClients.createDefault();
HttpPost httpPost = new HttpPost(url);
CloseableHttpResponse response = null;
try{
response = httpclient.execute(httpPost);
StatusLine statusLine = response.getStatusLine();
HttpEntity entity = response.getEntity();
if(statusLine != null && statusLine.getStatusCode() >= 300){
throw new HttpResponseException(statusLine.getStatusCode(),
statusLine.getReasonPhrase());
}
if(entity == null){
throw new ClientProtocolException("response contains no content");
}
entity.writeTo(os);
return true;
}catch(IOException e){
e.printStackTrace();
return false;
}finally{
if(response != null){
try{
response.close();
}catch(IOException e){
e.printStackTrace();
}
}
}
}
}
中間代理servlet代碼如下:
@WebServlet("/HttpclientServlet")
public class HttpclientServlet extends HttpServlet
{
private static final long serialVersionUID = 1L;
public HttpclientServlet()
{
super();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
this.doPost(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
String url = request.getParameter("url");
if(url != null){
if(!HttpUtil.returnResponseOfUrl(url, response.getOutputStream())){
if(!HttpUtil.returnResponseOfUrl(url, response.getOutputStream())){ // 如果出錯,再試一次
// log.error("url:" + url);
};
}
}
}
}
html4項目中的訪問頁面代碼如下:
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="keywords" content="jsonp">
<meta name="description" content="jsonp">
<title>jsonp</title>
<style type="text/css">
*{margin:0;padding:0;}
div{width:600px;height:100px;margin:20px auto;}
</style>
</head>
<body>
<div>
<a href="javascript:;">jsonp測試</a>
</div>
<script type="text/javascript" src="js/jquery-1.11.1.js"></script>
<script type="text/javascript">
$(function(){
$("a").on("click", function(){
$.ajax({
type:"post",
url:"http://localhost:8888/html4/HttpclientServlet?url="+ecodeURIComponent("http://localhost:8080/html5/JsonServlet"),
success:function(data) {
console.log(data);
console.log(data.name);
console.log(data.age);
var user = JSON.parse(data);
console.log(user.name);
console.log(user.age);
}
});
})
});
</script>
</body>
</html>
上面通過:url=http://localhost:8080/html5/JsonServlet 將我們最終要跨域訪問的url地址傳給自己服務器下的 HttpclientServlet. 然后在 HttpclientServlet 中使用httpclient訪問 跨域 url 中的servlet,成功之后,將返回的結果返回給客戶端。
html5項目中被 跨域 訪問的servlet代碼如下:
@WebServlet("/JsonServlet")
public class JsonServlet extends HttpServlet
{
private static final long serialVersionUID = 4335775212856826743L;
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
User user = new User();
user.setName("yuanfang");
user.setAge(100);
Object obj = JSON.toJSON(user);
System.out.println(user); // com.tz.servlet.User@164ff87
System.out.println(obj); // {"age":100,"name":"yuanfang"}
response.getWriter().println(obj);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
this.doPost(request, response);
}
}
啟動8888和8080端口的tomcat,訪問 http://localhost:8888/html4/jsonp.html ,結果如下:

我們注意到第二和第三項都打印的是 undefined ,這是因為 中間代理的 HttpclientServlet,使用的是直接輸出流的方式,所以最終返回的結果不是Json對象,而是字符串,所以需要使用 var user = JSON.parse(data); 來進行解析成 javascript對象就可以,所以第四和第五項都正常輸出了結果。
如果想返回的是json對象,加一句代碼 response.setContentType("text/json;charset=utf-8"); 就可以:
if(url != null){
response.setContentType("text/json;charset=utf-8");
if(!HttpUtil.returnResponseOfUrl(url, response.getOutputStream())){
if(!HttpUtil.returnResponseOfUrl(url, response.getOutputStream())){ // 如果出錯,再試一次
// log.error("url:" + url);
};
}
}
這樣的話,瀏覽器在看到 contentType: "text/json;charset=utf-8" 時,它的js執行引擎會自動幫助我們將字符串解析成json對象。也就是相當於自動調用了 JSON.parse(data) 的效果。
簡單吧 ^__^
