基于jsoup的Java服务端http(s)代理程序-代理服务器Demo
亲爱的开发者朋友们,知道百度网址翻译么?他们为何能够翻译源网页呢,iframe可是不能跨域操作的哦,那么可以用代理实现。直接上代码:
本Demo基于MVC写的,灰常简单,copy过去,简单改改就可以用的哦。
//Action层
/**
* 网址翻译代理服务器接口层
* @Description: 此接口层可完成对所请求网址的代理,实现同域访问
* @author zhanglongping
* @CreateDate: 2016-8-23 上午10:52:49
*/ @At("/proxy")
public class ProxyModule { /**
* 获取网页
* @return
* @author zhanglongping
* @date 2016-8-23 上午10:54:13
*/
@At("/gethtml")
@Ok("Raw")
@Authority("")
public Object gethtml(@Param("yeekit_proxy_url") String url,HttpServletRequest request, HttpServletResponse response){
try { String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; String html = new ProxyUtils().getUrlMap(url,basePath);
// return html;
InputStream is = new StringInputStream(html);
BufferedReader in = new BufferedReader(new InputStreamReader(is,"UTF-8")); String line;
PrintWriter out = response.getWriter();
while ((line = in.readLine()) != null) {
out.println(line);
}
out.flush();
in.close();
} catch (Exception e) {
e.printStackTrace();
}
return null;
} /**
* 使用GET提交到目标服务器。
*
* @param request
* @param response
* @param targetUrl
* @throws IOException
*/
@At("/forward")
@Ok("Raw")
@Authority("")
public Object urlRedirect(@Param("yeekit_proxy_url") String targetUrl,HttpServletRequest request, HttpServletResponse response) throws IOException { if(targetUrl.endsWith(".htm") || targetUrl.endsWith(".html") || targetUrl.endsWith(".shtml")){
try { String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; String html = new ProxyUtils().getUrlMap(targetUrl,basePath);
// return html;
InputStream is = new StringInputStream(html);
BufferedReader in = new BufferedReader(new InputStreamReader(is,"UTF-8")); String line;
PrintWriter out = response.getWriter();
while ((line = in.readLine()) != null) {
out.println(line);
}
out.flush();
in.close();
} catch (Exception e) {
e.printStackTrace();
// return null;
} }else if(targetUrl.endsWith(".css") || targetUrl.endsWith(".js") || targetUrl.endsWith(".jpg")||
targetUrl.endsWith(".png") || targetUrl.endsWith(".svg") || targetUrl.endsWith(".gif")){
String fileName = targetUrl.split("/")[targetUrl.split("/").length-1];
// response.setHeader("Content-Disposition", "attachment; filename="
// + java.net.URLEncoder.encode(fileName, "UTF-8"));
//图片的名称
String imgName = fileName;
//名称转码,避免中文乱码
imgName = new String(imgName.getBytes("iso8859-1"),"UTF-8");
//图片的资源地址,http://10.80.3.229:8081/mediaserver/574fe515e30ab97c9068d2e1
//这是媒体服务器返回的地址,因为是网络地址,所以需要使用HttpURLConnection去获取图片
String imgUrl = targetUrl;
//输入流,用来读取图片
InputStream ins = null;
HttpURLConnection httpURL = null;
try{
URL url = new URL(imgUrl);
//打开一个网络连接
httpURL = (HttpURLConnection)url.openConnection();
//设置网络连接超时时间
httpURL.setConnectTimeout(3000);
//设置应用程序要从网络连接读取数据
httpURL.setDoInput(true);
//设置请求方式
httpURL.setRequestMethod("GET");
//获取请求返回码
int responseCode = httpURL.getResponseCode();
if(responseCode == 200){
//如果响应为“200”,表示成功响应,则返回一个输入流
ins = httpURL.getInputStream();
//设置response响应头
//encodeChineseDownloadFileName()用来解决文件名为中文的问题,方法体在下面
if(fileName.indexOf(".css")>-1){
response.setContentType("text/css");
}
response.setHeader("content-disposition", "attachment;filename="+ ProxyUtils.encodeChineseDownloadFileName(request,imgName));
//输出流到response中
byte[] data = new byte[1024];
int len = 0;
//输出流
OutputStream out = response.getOutputStream();
while((len = ins.read(data)) > 0){
out.write(data, 0, len);
}
out.flush();
ins.close(); }
}catch(Exception e){
System.out.println("下载附件图片出错!"+targetUrl);
e.printStackTrace();
}
}
return null; }
工具类
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern; import javax.servlet.http.HttpServletRequest; import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils;
import org.jsoup.Connection;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.select.Elements; /**
* 译库网址翻译代理服务工具类
*
* @Description:包含:提取HTML中网址,并转换为代理的网址服务地址;
* @author zhanglongping
* @CreateDate: 2016-8-23 上午10:15:08
* @UpdateUser: zhanglongping
* @UpdateDate: 2016-8-23 上午10:15:08
* @UpdateRemark: 说明本次修改内容
*/
public class ProxyUtils {
// public static void main(String[] args) throws IOException {
//// ProxyUtils pu = new ProxyUtils();
//// pu.getUrlMap("http://english.cas.cn");
// Connection conn = Jsoup.connect("http://www.bbc.com");
// Document doc_one = conn.get();
// System.out.println(doc_one);
// } /**
* 获取url哈希:key:源url value:代理url
* @param url
* @author zhanglongping
* @date 2016-8-23 上午10:42:41
*/
public String getUrlMap(String url,String basePath){
// String url_protocol = "",url_host = "";
try {
//特殊网址转换
url = transformation(url);
URL urlcurr = new URL(url);
// url_protocol = urlcurr.getProtocol();
// url_host = urlcurr.getHost();
String hostname = urlcurr.getProtocol()+"://"+urlcurr.getHost(); // String proxyHost = basePath; // String proxyHostName = proxyHost+"proxy/forward?yeekit_proxy_url="; Document doc_one; Connection conn = Jsoup.connect(hostname);
doc_one = conn.get();
doc_one.setBaseUri(hostname); // Elements links = doc_one.select("a[href]");
// Elements media = doc_one.select("[src]");
// Elements imports = doc_one.select("link[href]"); Elements head = doc_one.select("meta");
head.get(0).before("<base href=\""+hostname+"/"+"\" />");
//鼠标悬停翻译js脚本注入
//悬停脚本引用
String hover_js = "<script src=\""+basePath+"/yeekit_translate_url/js/yeekit_hover_trans.js\" type=\"text/javascript\"></script>";
String jquery_js = "<script src=\"http://cdn.bootcss.com/jquery/3.1.0/jquery.min.js\" type=\"text/javascript\"></script>";
head.get(0).after(jquery_js + hover_js);
// for (Element src : media) {
// String key = src.attr("abs:src");
// src.attr("src", proxyHostName+key);
// }
//
// for (Element link : imports) {
// String key = link.attr("abs:href");
// link.attr("href", proxyHostName+key);
// }
//
// for (Element link : links) {
// String key = link.attr("abs:href");
// link.attr("href", proxyHostName+key);
// } String dochtml = doc_one.html().toString(); //增强型处理 - 处理js脚本里静态资源地址引用
// List<String> list_src_img = getImgSrc(dochtml);
// for(String src:list_src_img){
// if(src.indexOf("./") > -1){
// dochtml = dochtml.replaceAll(src, proxyHostName+hostname+src.substring(1));
// }
// } // System.out.println(dochtml);
return dochtml;
} catch (IOException e) {
e.printStackTrace();
return null;
} } /**
* 内容获取
* @return
* @author zhanglongping
* @throws IOException
* @date 2016-8-30 下午5:44:31
*/
public String get_https_html(String url) throws IOException{ URL urlcurr = new URL(url);
String hostname = urlcurr.getProtocol()+"://"+urlcurr.getHost(); Document doc_one; Connection conn = Jsoup.connect(hostname);
doc_one = conn.post();
doc_one.setBaseUri(hostname); Elements head = doc_one.select("meta"); head.get(0).before("<base href=\""+hostname+"/"+"\" />"); String dochtml = doc_one.html().toString(); return dochtml;
} /*
* 解决文件为中文名的乱码问题
*/
public static String encodeChineseDownloadFileName(HttpServletRequest request, String pFileName) throws UnsupportedEncodingException{
String filename = null;
//获取请求头中的浏览器标识
String agent = request.getHeader("USER-AGENT");
if(agent != null){
if(agent.indexOf("Firefox") != -1){
//Firefox
filename = "=?UTF-8?B?" +
(new String(Base64.encodeBase64(pFileName.getBytes("UTF-8")))) + "?=";
}else if(agent.indexOf("Chrome") != -1){
//Chrome
filename = new String(pFileName.getBytes(), "ISO8859-1");
}else{
//IE7+
filename = URLEncoder.encode(pFileName, "UTF-8");
//替换空格
filename = StringUtils.replace(filename, "+", "%20");
}
}else{
filename = pFileName;
}
return filename;
} /**
* 获取img标签中的src值
* @param content
* @return
*/
public List<String> getImgSrc(String content){ List<String> list = new ArrayList<String>();
//目前img标签标示有3种表达式
//<img alt="" src="1.jpg"/> <img alt="" src="1.jpg"></img> <img alt="" src="1.jpg">
//开始匹配content中的<img />标签
Pattern p_img = Pattern.compile("<(img|IMG)(.*?)(/>|></img>|>)");
Matcher m_img = p_img.matcher(content);
boolean result_img = m_img.find();
if (result_img) {
while (result_img) {
//获取到匹配的<img />标签中的内容
String str_img = m_img.group(2); //开始匹配<img />标签中的src
Pattern p_src = Pattern.compile("(src|SRC)=(\"|\')(.*?)(\"|\')");
Matcher m_src = p_src.matcher(str_img);
if (m_src.find()) {
String str_src = m_src.group(3);
list.add(str_src);
}
//结束匹配<img />标签中的src //匹配content中是否存在下一个<img />标签,有则继续以上步骤匹配<img />标签中的src
result_img = m_img.find();
}
}
return list;
} /**
* 特殊网址转换
* @param url
* @return
* @author zhanglongping
* @date 2016-8-30 下午6:18:48
*/
public String transformation(String url){
//百度的二级域名www.baidu.com重定向存在问题
if(url.equals("http://www.baidu.com")){
url = "http://baidu.com";
} return url;
}
}
基于jsoup的Java服务端http(s)代理程序-代理服务器Demo的更多相关文章
- java服务端实现微信小程序内容安全
请参考微信官方文档:https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/sec-check/security.i ...
- Java 服务端监控方案(四. Java 篇)
http://jerrypeng.me/2014/08/08/server-side-java-monitoring-java/ 这个漫长的系列文章今天要迎来最后一篇了,也是真正与 Java 有关的部 ...
- Java 服务端入门和进阶指南
作者:谢龙 链接:https://www.zhihu.com/question/29581524/answer/44872235 来源:知乎 著作权归作者所有,转载请联系作者获得授权. 现在互联网上资 ...
- 那些年,我们见过的 Java 服务端乱象
导读 查尔斯·狄更斯在<双城记>中写道:“这是一个最好的时代,也是一个最坏的时代.” 移动互联网的快速发展,出现了许多新机遇,很多创业者伺机而动:随着行业竞争加剧,互联网红利逐渐消失,很多 ...
- 那些年,我们见过的 Java 服务端“问题”
导读 明代著名的心学集大成者王阳明先生在<传习录>中有云: 道无精粗,人之所见有精粗.如这一间房,人初进来,只见一个大规模如此.处久,便柱壁之类,一一看得明白.再久,如柱上有些文藻,细细都 ...
- 那些年,我们见过的Java服务端乱象
导读 查尔斯·狄更斯在<双城记>中写道:“这是一个最好的时代,也是一个最坏的时代.”移动互联网的快速发展,出现了许多新机遇,很多创业者伺机而动:随着行业竞争加剧,互联网红利逐渐消失,很多创 ...
- 俯瞰 Java 服务端开发
原文首发于 github ,欢迎 star . Java 服务端开发是一个非常宽广的领域,要概括其全貌,即使是几本书也讲不完,该文将会提到许多的技术及工具,但不会深入去讲解,旨在以一个俯瞰的视角去探寻 ...
- Java服务端性能优化
<Java程序性能优化>说性能优化包含五个层次:设计调优.代码调优.JVM调优.数据库调优.操作系统调优. 常用的几个代码优化方案: 使用单例 对于IO处理.数据库连接.配置文件解析加载等 ...
- RPC学习--C#使用Thrift简介,C#客户端和Java服务端相互交互
本文主要介绍两部分内容: C#中使用Thrift简介 用Java创建一个服务端,用C#创建一个客户端通过thrift与其交互. 用纯C#实现Client和Server C#服务端,Java客户端 其中 ...
随机推荐
- 第四-generation音频:互联网智能声音会火
我把声音分成四个年龄:传统的立体声插头线-蓝牙音响-wifi发出声音-智能声音. 传统的立体声插头线:传统的声音,您必须使用电缆和其他输入源.这样的声音是现在市场上最流行的音频上. 蓝牙音响:蓝牙无线 ...
- Codeforces 338D GCD Table 中国剩余定理
主题链接:点击打开链接 特定n*m矩阵,[i,j]分值为gcd(i,j) 给定一个k长的序列,问能否匹配上 矩阵的某一行的连续k个元素 思路: 我们要求出一个解(i,j) 使得 i<=n &am ...
- rails 4.0.2 + mongoid 对mongodb进行增删改查
新建项目 rails new mongoid_app --skip-active-record --skip-test-unit --skip-bundle create create README. ...
- python字典构造函数dict(mapping)解析
Python字典的构造函数有三个,dict().dict(**args).dict(mapping),当中第一个.第二个构造函数比較好理解也比較easy使用, 而dict(mapping)这个构造函数 ...
- Computer Science 学习第四章--CPU 指令集和指令处理
Instruction set Y86 指令集 运算符:addl, subl, andl, and xorl 跳转符:jmp,jle,jl,je,jne,jge, andjg 条件符:cmovle, ...
- SQL入门学习5-函数、为此、CASE表达式
6-1. 各种各样的函数 函数的种类 算数函数 字符串函数 日期函数 转换函数 聚合函数 1.1算术函数 数据类型:NUMERIC 是大多数DBMS都支持的一种数据类型. 通过NUMBERIC(全体位 ...
- EF操作sqlite数据库时的项目兼容性问题
问题:vs2015打不开vs2010建的操作sqlite的实体数据模型edmx文件 原因: 当前电脑必须先安装:驱动库及sqlite的vs拓展 正常情况下安装驱动和拓展后,vs2015就应该可以正常打 ...
- 使用eclips发展java当闪回的问题
近期開始android的开发学习.当然要先从java入手了.我选择eclips作为开发的IDE,在測试java代码例子时,假设我的代码是能够出现系统自己主动代码补齐时eclips就会立马闪退. 刚開始 ...
- 【核心研究】消息队列_MessageQueue
消息队列排队过程中的消息.这第一条消息将首先被处理.但假设消息本身指定要处理的时间.我们必须等待,直到时间的消息处理能力.新闻MessageQueue正在使用Message类的表示,队列中的邮件保存结 ...
- UVALive 5099 Nubulsa Expo 全球最小割 非网络流量 n^3
主题链接:点击打开链接 意甲冠军: 给定n个点m条无向边 源点S 以下m行给出无向边以及边的容量. 问: 找一个汇点,使得图的最大流最小. 输出最小的流量. 思路: 最大流=最小割. 所以题意就是找全 ...