Java反向代理案例

wen java案例 3

本文目录导读:

Java反向代理案例

  1. 简单HTTP反向代理(基于Socket)
  2. 使用Apache HttpClient的实现(功能更强大)
  3. 高性能反向代理(Netty实现)
  4. 使用Spring Cloud Gateway(微服务场景)
  5. Nginx反向代理配置(生产环境推荐)
  6. 配置文件和依赖
  7. 关键特性说明
  8. 使用场景

我来为您提供一个完整的Java反向代理实现案例,包含多种实现方式。

简单HTTP反向代理(基于Socket)

import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;
import java.io.*;
import java.net.*;
import java.util.concurrent.Executors;
/**
 * 简单的HTTP反向代理服务器
 */
public class SimpleReverseProxy {
    public static void main(String[] args) throws IOException {
        // 创建HTTP服务器监听8080端口
        HttpServer server = HttpServer.create(new InetSocketAddress(8080), 0);
        // 设置代理处理
        server.createContext("/", new ProxyHandler());
        server.setExecutor(Executors.newFixedThreadPool(10));
        System.out.println("代理服务器启动在 8080 端口...");
        server.start();
    }
    static class ProxyHandler implements HttpHandler {
        // 目标服务器
        private static final String TARGET_HOST = "example.com";
        private static final int TARGET_PORT = 80;
        @Override
        public void handle(HttpExchange exchange) throws IOException {
            // 构建目标URL
            String path = exchange.getRequestURI().getPath();
            String query = exchange.getRequestURI().getQuery();
            String targetUrl = "http://" + TARGET_HOST + ":" + TARGET_PORT + path;
            if (query != null && !query.isEmpty()) {
                targetUrl += "?" + query;
            }
            try {
                // 创建到目标服务器的连接
                URL url = new URL(targetUrl);
                HttpURLConnection connection = (HttpURLConnection) url.openConnection();
                connection.setRequestMethod(exchange.getRequestMethod());
                // 复制请求头
                exchange.getRequestHeaders().forEach((key, values) -> {
                    values.forEach(value -> connection.setRequestProperty(key, value));
                });
                // 处理请求体
                if (exchange.getRequestMethod().equals("POST") || 
                    exchange.getRequestMethod().equals("PUT")) {
                    connection.setDoOutput(true);
                    try (OutputStream outputStream = connection.getOutputStream();
                         InputStream inputStream = exchange.getRequestBody()) {
                        byte[] buffer = new byte[4096];
                        int bytesRead;
                        while ((bytesRead = inputStream.read(buffer)) != -1) {
                            outputStream.write(buffer, 0, bytesRead);
                        }
                    }
                }
                // 获取响应
                int responseCode = connection.getResponseCode();
                // 设置响应头
                exchange.getResponseHeaders().set("Content-Type", 
                    connection.getContentType() != null ? 
                    connection.getContentType() : "text/html");
                // 发送响应
                exchange.sendResponseHeaders(responseCode, 0);
                // 复制响应体
                try (InputStream inputStream = connection.getInputStream();
                     OutputStream outputStream = exchange.getResponseBody()) {
                    byte[] buffer = new byte[4096];
                    int bytesRead;
                    while ((bytesRead = inputStream.read(buffer)) != -1) {
                        outputStream.write(buffer, 0, bytesRead);
                    }
                }
            } catch (Exception e) {
                // 错误响应
                String error = "代理错误: " + e.getMessage();
                exchange.sendResponseHeaders(500, error.length());
                try (OutputStream os = exchange.getResponseBody()) {
                    os.write(error.getBytes());
                }
            } finally {
                exchange.close();
            }
        }
    }
}

使用Apache HttpClient的实现(功能更强大)

import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.client.methods.*;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.IOException;
import java.net.URI;
/**
 * 基于Servlet的HTTP反向代理
 */
public class ServletReverseProxy extends HttpServlet {
    private final CloseableHttpClient httpClient;
    private final String targetServer;
    public ServletReverseProxy() {
        // 初始化HTTP客户端
        this.httpClient = HttpClients.createDefault();
        // 目标服务器地址
        this.targetServer = "http://backend-server:8081";
    }
    @Override
    protected void service(HttpServletRequest request, 
                          HttpServletResponse response) 
            throws ServletException, IOException {
        // 构建目标URI
        String targetPath = buildTargetPath(request);
        String targetUrl = targetServer + targetPath;
        try {
            // 创建请求
            HttpUriRequest proxyRequest = createRequest(request, targetUrl);
            // 执行请求
            try (CloseableHttpResponse proxyResponse = 
                    httpClient.execute(proxyRequest)) {
                // 复制响应头
                response.setStatus(proxyResponse.getStatusLine().getStatusCode());
                for (org.apache.http.Header header : 
                        proxyResponse.getAllHeaders()) {
                    response.setHeader(header.getName(), header.getValue());
                }
                // 复制响应体
                HttpEntity entity = proxyResponse.getEntity();
                if (entity != null) {
                    response.getOutputStream().write(
                        EntityUtils.toByteArray(entity)
                    );
                }
            }
        } catch (Exception e) {
            response.setStatus(500);
            response.getWriter().write("代理错误: " + e.getMessage());
        }
    }
    private String buildTargetPath(HttpServletRequest request) {
        String path = request.getRequestURI();
        String query = request.getQueryString();
        if (query != null && !query.isEmpty()) {
            path += "?" + query;
        }
        return path;
    }
    private HttpUriRequest createRequest(HttpServletRequest request, 
                                        String targetUrl) {
        String method = request.getMethod();
        HttpUriRequest proxyRequest;
        switch (method) {
            case "POST":
                HttpPost post = new HttpPost(targetUrl);
                proxyRequest = post;
                break;
            case "PUT":
                HttpPut put = new HttpPut(targetUrl);
                proxyRequest = put;
                break;
            case "DELETE":
                HttpDelete delete = new HttpDelete(targetUrl);
                proxyRequest = delete;
                break;
            default:
                HttpGet get = new HttpGet(targetUrl);
                proxyRequest = get;
        }
        // 复制请求头
        java.util.Enumeration<String> headerNames = 
            request.getHeaderNames();
        while (headerNames.hasMoreElements()) {
            String headerName = headerNames.nextElement();
            String headerValue = request.getHeader(headerName);
            proxyRequest.setHeader(headerName, headerValue);
        }
        return proxyRequest;
    }
}

高性能反向代理(Netty实现)

import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.http.*;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
/**
 * Netty实现的高性能反向代理
 */
public class NettyReverseProxy {
    public static void main(String[] args) throws InterruptedException {
        // 创建事件循环组
        EventLoopGroup bossGroup = new NioEventLoopGroup(1);
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        EventLoopGroup targetGroup = new NioEventLoopGroup();
        try {
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            serverBootstrap.group(bossGroup, workerGroup)
                .channel(NioServerSocketChannel.class)
                .handler(new LoggingHandler(LogLevel.INFO))
                .childHandler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel ch) {
                        ChannelPipeline pipeline = ch.pipeline();
                        pipeline.addLast(new HttpServerCodec());
                        pipeline.addLast(new HttpObjectAggregator(65536));
                        pipeline.addLast(new ProxyHandler(targetGroup, "backend-server", 8081));
                    }
                });
            // 启动服务器
            Channel serverChannel = serverBootstrap.bind(8080).sync().channel();
            System.out.println("Netty反向代理启动在 8080 端口");
            serverChannel.closeFuture().sync();
        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
            targetGroup.shutdownGracefully();
        }
    }
    static class ProxyHandler extends SimpleChannelInboundHandler<FullHttpRequest> {
        private final EventLoopGroup targetGroup;
        private final String targetHost;
        private final int targetPort;
        public ProxyHandler(EventLoopGroup targetGroup, 
                           String targetHost, int targetPort) {
            this.targetGroup = targetGroup;
            this.targetHost = targetHost;
            this.targetPort = targetPort;
        }
        @Override
        protected void channelRead0(ChannelHandlerContext ctx, 
                                   FullHttpRequest request) {
            // 复制请求
            FullHttpRequest proxiedRequest = request.copy();
            // 创建到目标服务器的连接
            Bootstrap bootstrap = new Bootstrap()
                .group(targetGroup)
                .channel(NioSocketChannel.class)
                .handler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel ch) {
                        ch.pipeline().addLast(new HttpClientCodec());
                        ch.pipeline().addLast(new HttpObjectAggregator(65536));
                        ch.pipeline().addLast(new ResponseHandler(ctx));
                    }
                });
            // 连接到目标服务器并发送请求
            bootstrap.connect(targetHost, targetPort).addListener(
                (ChannelFuture future) -> {
                    if (future.isSuccess()) {
                        future.channel().writeAndFlush(proxiedRequest);
                    } else {
                        ctx.writeAndFlush(new DefaultFullHttpResponse(
                            HttpVersion.HTTP_1_1, 
                            HttpResponseStatus.BAD_GATEWAY
                        ));
                        ctx.close();
                    }
                }
            );
        }
        @Override
        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
            cause.printStackTrace();
            ctx.close();
        }
    }
    static class ResponseHandler extends SimpleChannelInboundHandler<FullHttpResponse> {
        private final ChannelHandlerContext clientContext;
        public ResponseHandler(ChannelHandlerContext clientContext) {
            this.clientContext = clientContext;
        }
        @Override
        protected void channelRead0(ChannelHandlerContext ctx, 
                                   FullHttpResponse response) {
            // 转发响应到客户端
            clientContext.writeAndFlush(response.copy());
            // 关闭连接
            ctx.close();
        }
        @Override
        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
            cause.printStackTrace();
            ctx.close();
        }
    }
}

使用Spring Cloud Gateway(微服务场景)

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.annotation.Bean;
@SpringBootApplication
public class GatewayApplication {
    public static void main(String[] args) {
        SpringApplication.run(GatewayApplication.class, args);
    }
    @Bean
    public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
        return builder.routes()
            // 用户服务路由
            .route("user-service", r -> r
                .path("/api/user/**")
                .filters(f -> f
                    .stripPrefix(2)
                    .addResponseHeader("X-Proxied-By", "Gateway")
                    .retry(3)
                    .circuitBreaker(c -> c
                        .setName("userServiceCB")
                        .setFallbackUri("forward:/fallback/user")))
                .uri("http://localhost:8081/"))
            // 订单服务路由
            .route("order-service", r -> r
                .path("/api/order/**")
                .filters(f -> f
                    .stripPrefix(2)
                    .addRequestHeader("X-Trace-Id", 
                        "trace-" + System.currentTimeMillis()))
                .uri("http://localhost:8082/"))
            // 负载均衡示例
            .route("load-balanced", r -> r
                .path("/api/load/**")
                .uri("lb://LOAD-BALANCED-SERVICE"))
            .build();
    }
}

Nginx反向代理配置(生产环境推荐)

# nginx.conf
upstream backend_servers {
    ip_hash;  # 会话保持
    server backend1.example.com:8080 weight=3;
    server backend2.example.com:8080 weight=2;
    server backend3.example.com:8080 backup;
}
server {
    listen 80;
    server_name example.com;
    # 基本反向代理
    location /api/ {
        proxy_pass http://backend_servers;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
    # WebSocket代理
    location /ws/ {
        proxy_pass http://websocket_backend;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
    # 静态文件缓存
    location /static/ {
        proxy_pass http://static_servers;
        proxy_cache static_cache;
        proxy_cache_valid 200 304 1h;
        expires 1h;
    }
    # 负载均衡
    upstream websocket_backend {
        least_conn;  # 最少连接
        server ws1.example.com:9090;
        server ws2.example.com:9090;
    }
}

配置文件和依赖

pom.xml依赖

<dependencies>
    <!-- Apache HttpClient -->
    <dependency>
        <groupId>org.apache.httpcomponents</groupId>
        <artifactId>httpclient</artifactId>
        <version>4.5.13</version>
    </dependency>
    <!-- Servlet API -->
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <version>4.0.1</version>
        <scope>provided</scope>
    </dependency>
    <!-- Netty -->
    <dependency>
        <groupId>io.netty</groupId>
        <artifactId>netty-all</artifactId>
        <version>4.1.75.Final</version>
    </dependency>
    <!-- Spring Cloud Gateway -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-gateway</artifactId>
        <version>3.1.3</version>
    </dependency>
</dependencies>

关键特性说明

  1. 请求转发:将客户端请求转发到后端服务器
  2. 响应缓存:缓存常用响应提高性能
  3. 负载均衡:分发请求到多个后端服务器
  4. URL重写:修改请求路径
  5. 安全过滤:添加认证、速率限制
  6. 日志记录:记录请求和响应信息
  7. 错误处理:处理后端故障和超时
  8. 协议转换:支持HTTP/HTTPS、WebSocket等

使用场景

  • 微服务网关:统一入口,路由分发
  • 负载均衡:分发流量到多个实例
  • 安全防护:隐藏后端结构,添加认证
  • 跨域处理:解决CORS问题
  • 协议转换:HTTP转WebSocket等
  • 流量控制:限流、熔断、重试

选择哪种实现方式取决于您的具体需求、性能要求和部署环境,对于生产环境,建议使用成熟的解决方案如Nginx或Spring Cloud Gateway。

抱歉,评论功能暂时关闭!