最近接手一个项目,新项目需要调用老项目的接口,但是老项目和新项目不再同一个域名下,所以必须进行跨域调用了,但是老项目又不能进行任何修改,所以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) 的效果

简单吧 ^__^

使用Httpclient来替代客户端的jsonp跨域解决方案的更多相关文章

  1. 跨域问题解决方案(HttpClient安全跨域 & jsonp跨域)

    1 错误场景 今天要把项目部署到外网的时候,出现了这样的问题, 我把两个项目放到自己本机的tomcat下, 进行代码调试, 运行 都没有问题的, 一旦把我需要调用接口的项目B放到其他的服务器上, 就会 ...

  2. 跨域问题解决方式(HttpClient安全跨域 &amp; jsonp跨域)

    1 错误场景 今天要把项目部署到外网的时候,出现了这种问题, 我把两个项目放到自己本机的tomcat下, 进行代码调试, 执行 都没有问题的, 一旦把我须要调用接口的项目B放到其它的server上, ...

  3. 深入剖析jsonp跨域原理

    在项目中遇到一个jsonp跨域的问题,于是仔细的研究了一番jsonp跨域的原理.搞明白了一些以前不是很懂的地方,比如: 1)jsonp跨域只能是get请求,而不能是post请求: 2)jsonp跨域的 ...

  4. webapi 跨域访问设置基于jsonp跨域

    JSONP实现跨域 Web API并没有提供JSONP  Formatter,但是这并不能影响我们前进的脚步,我们可以自定义Formatter来实现JSONP功能.既然是利用JSONP跨域,那么就得简 ...

  5. 原生JS封装Ajax插件(同域&&jsonp跨域)

    抛出一个问题,其实所谓的熟悉原生JS,怎样的程度才是熟悉呢? 最近都在做原生JS熟悉的练习... 用原生Js封装了一个Ajax插件,引入一般的项目,传传数据,感觉还是可行的...简单说说思路,如有不正 ...

  6. jsonp 跨域请求

    背景: JavaScript是一种在Web开发中经常使用的前端动态脚本技术.在JavaScript中,有一个很重要的安全性限制,被称为"Same-Origin Policy"(同源 ...

  7. 我的jsonp跨域问题

    关于jsonp跨域问题,在这个方面也是了解一点点,先记录下来,主要作为以后查看,之前下载并安装过wampserver,了解到了jsonp和json的区别,现在谈谈跨域这个问题: 首先什么是跨域,简单地 ...

  8. JSONP跨域的原理解析( 一种脚本注入行为)

    JavaScript是一种在Web开发中经常使用的前端动态脚本技术.在JavaScript中,有一个很重要的安全性限制, 被称为“some-Origin Policy”(同源策略).这一策略对于Jav ...

  9. jsonp跨域问题

    JSONP是一个非官方的协议,它允许在服务器端集成Script tags返回至客户端,通过javascript callback的形式实现跨域访问(这仅仅是JSONP简单的实现形式). 同源策略限制 ...

随机推荐

  1. CentOS6.5菜鸟之旅:U盘安装CentOS64位

    一.前言 之前下载了个CentOS7 32位版,一下就安装成功了,但由于其目录结构等与之前的CentOS版本有很大的不同,加上教程不多不利于我这种菜鸟学习,于是决定重装CentOS6.5来学习.本篇用 ...

  2. Linq专题之Lambda表达式

    这一节我们讲的Lambda表达式跟匿名函数有关.Lambda表达式就是一个匿名函数,它可以包含表达式和语句,并且可以创建委托和表达式树. Lambda表达式的组成: 输入参数.Lambda运算符(=& ...

  3. 【C++】第1章 在VS2015中用C++编写控制台应用程序

    分类:C++.VS2015 创建日期:2016-06-12 一.简介 看到不少人至今还在用VC 6.0开发工具学习C++,其实VC 6.0开发工具早就被淘汰了.这里仅介绍学习C++时推荐使用的两种开发 ...

  4. 【JS复习笔记】03 继承

    关于继承 好吧,说到底JS还是原型继承的,而不是类继承.所以在这个上面要经常用到prototype去继承另一个对象. 所有的构造器函数都约定命名为首字母大写的形式,并且不以首字母大写的形式拼写任何其它 ...

  5. 小白学Linux--虚拟机下安装Ubuntu16

    最近接收到任务,说是下半年可能要搞全文检索.听到后顿时炸锅了,一方面是对新技术的兴奋(当然主要还是这技术比较值钱),另一方面,我TM连Linux都不会玩,怎么搞全文检索.怀揣着对开源世界的无线向往(恐 ...

  6. sqlite3之基本操作(一)

    简单的介绍 SQLite数据库是一款非常小巧的嵌入式开源数据库软件,也就是说没有独立的维护进程,所有的维护都来自于程序本身.它是遵守ACID的关联式数据库管理系统,它的设计目标是嵌入式的,而且目前已经 ...

  7. 两种设计模式(1)==>>“简单工厂”

    我们以做一个计算器为例,给大家介绍简单工厂的应用: 效果: 这里我们使用 继承 ,虚方法, 简单工厂的设计模式来完成 首先,我们除了搭好窗体外,我们应该把我们的一些类准备好: 1.计算的父类Calcu ...

  8. Angularjs,WebAPI 搭建一个简易权限管理系统 —— 系统业务与实现(三)

    目录 前言 Angularjs名词与概念 Angularjs 基本功能演示 系统业务与实现 WebAPI项目主体结构 Angularjs 前端主体结构 系统业务与实现(二) 上一章我们讲解的 Angu ...

  9. C#枚举类型和结构体

    注意:枚举类型和结构体都属于值类型. 结构体:就是一个自定义的集合,里面可以放各种类型的元素,用法大体跟集合一样. 一.定义的方法: struct student { public int nianl ...

  10. 【GOF23设计模式】命令模式

    来源:http://www.bjsxt.com/ 一.[GOF23设计模式]_命令模式.数据库事务机制底层架构实现.撤销和回复 package com.test.command; public cla ...