使用Java实现类似nginx的转发请求

因为需要将应用服务器之外的另一台文件服务器的ip地址隐藏,并且需要记录文件访问记录,以及需要对request的请求做一些处理,nginx实现这些相当麻烦,因此直接用Java写一个反向代理,简单明了。

utils

相当于使用流拷贝的方式,将获取到的newUrl的response,拷贝到客户请求的response中,这样就实现了转发


import org.springframework.http.HttpMethod;
import org.springframework.http.client.ClientHttpRequest;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.util.StreamUtils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;

public class ProxyUtil {

    public static void proxy(URI newUri, HttpServletRequest request, HttpServletResponse response) throws IOException {
        String methodName = request.getMethod();
        HttpMethod httpMethod = HttpMethod.resolve(methodName);
        if(httpMethod == null) {
            return;
        }
        ClientHttpRequest delegate = new SimpleClientHttpRequestFactory().createRequest(newUri, httpMethod);
        Enumeration<String> headerNames = request.getHeaderNames();
        // 设置请求头
        while (headerNames.hasMoreElements()) {
            String headerName = headerNames.nextElement();
            Enumeration<String> v = request.getHeaders(headerName);
            List<String> arr = new ArrayList<>();
            while (v.hasMoreElements()) {
                arr.add(v.nextElement());
            }
            delegate.getHeaders().addAll(headerName, arr);
        }
        StreamUtils.copy(request.getInputStream(), delegate.getBody());
        // 执行远程调用
        ClientHttpResponse clientHttpResponse = delegate.execute();
        response.setStatus(clientHttpResponse.getStatusCode().value());
        // 设置响应头
        clientHttpResponse.getHeaders().forEach((key, value) -> value.forEach(it -> {
            response.setHeader(key, it);
        }));
        StreamUtils.copy(clientHttpResponse.getBody(), response.getOutputStream());
    }
}

controller

//经过/proxy/**的地址都会返回192.168.1.1的结果,相当于nginx反向代理的效果
@RequestMapping(value = "/proxy/**")
public void proxy(HttpServletRequest request, HttpServletResponse response){
    String path = uri.getPath();
    URI newUri = new URI("http://192.168.1.1" + path.replace("/proxy",""))
    ProxyUtil.proxy(newUri,request,response);
}

这样加上后,所有经过/proxy/**的地址都会走一遍Java代码,你可以在代码中增加登录验证等功能

评论区
头像
    头像
    HAH