在前面正向代理和反向代理(一)中介绍了正向/反向代理的基本概念后,今天用Java模拟实现一个最简单的反向代理。
如上图所示,我们要实现的就是中间的反向代理部分,而真正的应用就隐藏在了反向代理后面,这样就能简单起到防止真正的应用直接暴露在攻击者的范围之内(这种保护手段也只是一种网络安全防护中一种基本的防护手段而已,并不能绝对保障应用的安全)。通过对反向代理的理解,我们实现一个最简单的反向代理服务器的功能就是要做请求的转发,把用户的请求转发给真正的应用即可。
首先在本地启动一个真正的应用:
@SpringBootApplication @RestController public class SpringbootServerApplication { public static void main(String[] args) { SpringApplication.run(SpringbootServerApplication.class, args); } @GetMapping("/hello") public String hello(@RequestParam(value = "name", defaultValue = "real server is here") String name) { return String.format("this is %s", name); } }我们可以通过Springboot来在本地启动一个简单的应用程序,并建立一个简单的controller映射/hello:启动应用后,正常访问:
http://localhost:7070/hello我们通过直接访问应用的真实地址:localhost:7070/hello来获取了请求的结果,下面开始建立一个反向代理,并通过反向代理转发我们的请求来访问真正应用的返回结果。
新建一个新的Springboot应用作为反向代理服务,然后增加一个filter,代码如下:
@Component @Slf4j public class TransactionFilter implements Filter { @Override public void doFilter( ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest req = (HttpServletRequest) request; HttpServletResponse res = (HttpServletResponse) response; String result = forwardRequest(req.getRequestURL().toString()); res.getWriter().println(result); } private String forwardRequest(String url) throws IOException { CloseableHttpClient httpclient = HttpClients.createDefault(); HttpGet httpGet = new HttpGet(url.replaceAll("8080","7070")); CloseableHttpResponse response = null; String content = ""; try{ response = httpclient.execute(httpGet); content = EntityUtils.toString(response.getEntity(),"UTF-8"); log.info(content); }finally { if (response != null) response.close(); httpclient.close(); } return content; } }我们通过实现Filter接口中doFilter方法来过滤用户传过来的请求,然后通过forwardRequest方法对用户请求进行转发,这里的转发的做法其实就是去再次请求真正的应用服务的接口,因为这里不管是代理服务还是真正的应用服务都是在本地启动的,所以host是一致的,唯一不同的就是端口号,我们这里真正的应用是在7070端口启动的,而代理服务是在8080端口启动的,所以只要替换端口号就可以,然后将请求得到的响应结果输出即可。
来看一下效果,我们直接访问代理服务器:
http://localhost:8080/hello可以看到通过访问反向代理得到了应用结果。
以上主要模拟构造一个最简单的反向代理Demo,来帮助理解反向代理的应用场景和原理,一个真正产品级的反向代理要考虑的情况有很多,除了安全防御考虑外,还有负载均衡、高可用等特性值得思考和研究,比较出名的反向代理的解决方案有nginx和openresty。