使用Java实现nginx反向代理的功能

需求

访问某个url后缀时,例如:/abc/*,自动路由到指定http服务地址http://myhost/*

代码

httpServer.createContext("/abc", BeanFactory.proxyHandler("yourhost:8080"));

反向代理处理器

public class ProxyHandler implements HttpHandler {

    private final static Logger log = Logger.getLogger(ProxyHandler.class.getName());

    private final static List<String> RESERVED_HEADERS = List.of("connection", "host", "content-length");

    private final String contextPath;
    private final String targetHost;

    public ProxyHandler(String contextPath, String targetHost) {
        this.contextPath = contextPath;
        this.targetHost = targetHost;
    }

    @Override
    public void handle(HttpExchange exchange) throws IOException {
        try (exchange) {
            URI requestURI = exchange.getRequestURI();
            String path = requestURI.getPath();
            // 重写请求路径,去除代理路径前缀
            String targetPath = path.substring(this.contextPath.length());
            HttpResponse<byte[]> response;
            try {
                response = this.requestToTargetHost(this.targetHost,
                        targetPath,
                        exchange.getRequestHeaders(),
                        exchange.getRequestMethod(),
                        exchange.getRequestBody().readAllBytes());
                byte[] bytes = response.body();
                for (Map.Entry<String, List<String>> entry : response.headers().map().entrySet()) {
                    if (entry.getKey().equalsIgnoreCase("content-type")) {
                        exchange.getResponseHeaders().put(entry.getKey(), entry.getValue());
                    }
                }
                exchange.sendResponseHeaders(200, bytes.length);
                exchange.getResponseHeaders().set("Access-Control-Allow-Origin", "*");

                OutputStream responseOutputStream = exchange.getResponseBody();
                responseOutputStream.write(bytes);
                responseOutputStream.flush();
                responseOutputStream.close();
            } catch (IOException e) {
                if (e instanceof ConnectException) {
                    log.severe("ConnectException: " + e);
                    responseError(exchange, "Connect failed.");
                } else {
                    log.severe("IOException: " + e);
                    responseError(exchange, "Network input error");
                }
            } catch (InterruptedException e) {
                log.severe("InterruptedException: " + e);
                responseError(exchange, "Service is not available.");
            }
        }
    }

    private static void responseError(HttpExchange exchange, byte[] bytes) throws IOException {
        exchange.sendResponseHeaders(502, bytes.length);
        exchange.getResponseHeaders().set("Access-Control-Allow-Origin", "*");
        OutputStream responseOutputStream = exchange.getResponseBody();
        responseOutputStream.write(bytes);
        responseOutputStream.flush();
        responseOutputStream.close();
    }

    private static void responseError(HttpExchange exchange, String message) throws IOException {
        byte[] bytes = message.getBytes();
        responseError(exchange, bytes);
    }

    HttpResponse<byte[]> requestToTargetHost(String targetHost, String targetUri, Headers headers, String method, byte[] bytes) throws IOException, InterruptedException {
        try (HttpClient httpClient = HttpClient.newBuilder().build()) {
            String prefix = targetHost.contains("http://") || targetHost.contains("https://") ? "" : "http://";
            String hostAndUri = prefix + targetHost + targetUri;
            HttpRequest.Builder builder = HttpRequest.newBuilder();
            for (Map.Entry<String, List<String>> entry : headers.entrySet()) {
                if (!RESERVED_HEADERS.contains(entry.getKey().toLowerCase())) {
                    builder.header(entry.getKey(), entry.getValue().getFirst());
                }
            }
            HttpRequest request = builder
                    .method(method, HttpRequest.BodyPublishers.ofByteArray(bytes))
                    .uri(URI.create(hostAndUri))
                    .build();
            return httpClient.send(request, HttpResponse.BodyHandlers.ofByteArray());
        }
    }

}

posted @   漠孤烟  阅读(267)  评论(0编辑  收藏  举报
编辑推荐:
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)
点击右上角即可分享
微信分享提示