JAVA实现的HTTP反向代理[smiley-http-proxy-servlet]学习
JAVA实现的HTTP反向代理[smiley-http-proxy-servlet]学习
 反向代理(Reverse Proxy)⽅式是指以代理服务器来接受internet上的连接请求,然后将请求转发给内部⽹络上的服务器,并将从服务器上得到的结果返回给internet上请求连接的客户端,此时代理服务器对外就表现为⼀个反向代理服务器。
 简单来说,你的反向代理服务器会接收请求,但其⾃⾝不处理该请求,⽽是对请求经过⼀些处理,例如添加⽇志、缓存、⾝份验证等服务,然后再将请求转发到相应的应⽤服务器中进⾏处理,最后将处理结果返回。
我⽬前的需求是,A应⽤需要访问B应⽤的报表页⾯,B应⽤没有源码,要求⾃动处理B应⽤的登录权限。避免⽤户重复登录。
1. 引⼊相关依赖
<dependency>
<groupId>org.mitre.dsmiley.httpproxy</groupId>
<artifactId>smiley-http-proxy-servlet</artifactId>
<version>1.11</version>
</dependency>
这个jar包,只有两个类,其中核⼼的就是 ProxyServlet,
作者重写了HttpServlet的相关⽅法。他复制了新的request为proxyRequest,
然后替换了地址和相关属性,并使⽤HttpClient将proxyRequest发送出去,
然后将接收到的proxyResponse的内容再复制给 HttpResponse 。
相当于中转站。具体请看源码。
2.spring使⽤:
2.l增加代理参数配置
# 设置代理
proxy:
servlet_url: /webappB/*
target_url: webappB_HOST_IP:8001/webappB #已有的app路径
其他demo
# servlet_url: /proxybaidu/*
# target_url: www.baidu
此处有⽞机:
为什么代理url的app⼦路径和⽬标url的app⼦路径要⼀致(都为/webappB/)呢?
这是因为: target_url页⾯⾥不⽌⽂本显⽰,还有其他资源的调⽤,⽐如图⽚,⽐如⾥⾯的js⼜调⽤了其他url.
这样的话,假如 target页⾯⾥某个图⽚的url是相对路径img/test.jpg (webappB_HOST_IP:8001/webappB/img/test.jpg); 你的代理页⾯app⼦路径⽤webappC,那么图⽚地址就成 /webappC/image/test.jpg; 这样app⼦url换了以后是不到图⽚地址的。
webappB_HOST_IP:8001/webappC/img/test.jpg 不存在。当然你也可以改下proxyServlet的源码,让它换成正确的url地址。如果不想改源码的话,那还是⼀致的⽐较好。少⿇烦。
2.2 注册servlet.
@Configuration
public class ProxyServletConfiguration {
/**
* 读取配置⽂件中路由设置
*/
@Value("${proxy.servlet_url}")
private String servlet_url;
/**
* 读取配置中代理⽬标地址
*/
@Value("${proxy.target_url}")
private String target_url;
@Bean
public Servlet createProxyServlet() {
/** 创建新的ProxyServlet */
return new ProxyServlet();
}
@Bean
public ServletRegistrationBean proxyServletRegistration() {
ServletRegistrationBean registrationBean = new ServletRegistrationBean(createProxyServlet(), servlet_url);
//设置⽹址以及参数
Map<String, String> params = ImmutableMap.of("targetUri", target_url, "log", "true");
registrationBean.setInitParameters(params);
return registrationBean;
}
/**
* fix springboot中使⽤proxyservlet的 bug.
*  github/mitre/HTTP-Proxy-Servlet/issues/83
*  stackoverflow/questions/8522568/why-is-httpservletrequest-inputstream-empty
* @param filter
* @return  关闭springboot ⾃带的 HiddenHttpMethodFilter 防⽌post提交的form数据流被提前消费
*/
  @Bean
  public FilterRegistrationBean registration(HiddenHttpMethodFilter filter) {
      FilterRegistrationBean registration = new FilterRegistrationBean(filter);代理服务器的设置
      registration.setEnabled(false);
    return registration;
  }
}
2.3测试。ok.
localhost:8080/proxybaidu/
2.4. 当然你也可以重新写个类,MyProxyServlet继承ProxyServlet.
重新其中的 execute⽅法。添加相关的功能。⽇志,权限登录等。
1    @Override
2protected HttpResponse execute(HttpServletRequest servletRequest, HttpServletResponse servletResponse,  3 HttpRequest proxyRequest) throws IOException {          //设置header⾥的授权信息
4        proxyRequest.setHeader("Authorization", "Basic " + getWebappBLoginAuth());
5        HttpResponse response = super.doExecute(servletRequest, servletResponse, proxyRequest);
6
7//        设置跨域,暂时不⽤。
8//        String origin = Header("origin");
9//        response.setHeader("Access-Control-Allow-Origin", origin);
10//        response.setHeader("Access-Control-Allow-Credentials", "true");
11//        response.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
12//        response.setHeader("Access-Control-Allow-Headers",
13//                "Accept,Authorization,Cache-Control,Content-Type,DNT,If-Modified-Since,Keep-Alive,Origin" +
14//                        ",User-Agent,X-Mx-ReqToken,X-Requested-With");
15return response;
16    }
2.5 后记:这个ProxyServlet 跟 nginx看着基本功能⼀样,都可以简单的反向代理。
不过扩展功能和IO性能肯定跟nginx没法⽐。但是这个是⽤java语⾔写的。
⽅便⼆次开发。不错!再次感谢[smiley-http-proxy-servlet]作者!

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。