• 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 。
    相当于中转站。具体请看源码。
    https://github.com/mitre/HTTP-Proxy-Servlet
    2.spring使用:
    2.1 application.yml增加代理参数配置
    # 设置代理
    proxy:
      servlet_url: /webappB/*
      target_url: https://webappB_HOST_IP:8001/webappB

    其他demo
     # servlet_url: /proxybaidu/*
      # target_url: https://www.baidu.com
    此处有玄机:
    为什么源url和目标url根路径要一致(都为/webappB/)呢?
    这是因为: target_url页面里不止文本显示,还有其他资源的调用,比如图片,比如里面的js又调用了其他url.
    这样的话,假如 target页面里某个图片的url是相对路径 img/test.jpg;
    你的页面上图的 /webappC/image/test.jpg; 这样host换了以后是找不到图片地址的。
    当然你也可以改下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.
    * https://github.com/mitre/HTTP-Proxy-Servlet/issues/83
    * https://stackoverflow.com/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
     2     protected 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 = servletRequest.getHeader("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");
    15         return response;
    16     }
    2.5 后记: 这个ProxyServlet 跟 nginx看着基本功能一样了,都可以反向代理了。
    不过扩展功能和IO性能肯定跟nginx没法比。但是这个是用java语言写的。
    方便二次开发。不错!再次感谢[smiley-http-proxy-servlet]作者!
  • 相关阅读:
    存储过程分页
    连接数据库
    绑定数据
    有关最近做的项目中用到的日期控件
    循环累加 由for _foreach
    打印gridview 中的所有内容
    list<>操作
    创建表两个主键外键~~~
    连接数据库sql server 2005
    WPF控件编程
  • 原文地址:https://www.cnblogs.com/java2sap/p/13200636.html
Copyright © 2020-2023  润新知