如何在Java/Kotlin中实现嵌入式请求转发代理?求方案及示例
可行的嵌入式代理方案及示例
1. Spring Boot(最简嵌入式方案)
自带嵌入式容器(Tomcat/Jetty/Undertow),快速实现转发逻辑,适合快速开发场景。
Kotlin示例
import org.springframework.boot.autoconfigure.SpringBootApplication import org.springframework.boot.runApplication import org.springframework.web.bind.annotation.PathVariable import org.springframework.web.bind.annotation.RequestMapping import org.springframework.web.bind.annotation.RestController import org.springframework.web.client.RestTemplate @SpringBootApplication @RestController class ProxyApplication { private val restTemplate = RestTemplate() private val targetBaseUrl = "http://localhost:5051" // 匹配所有以/my/path开头的请求,转发到目标服务器 @RequestMapping("/my/path/**") fun forwardRequest(@PathVariable("**") path: String): Any { val targetUrl = "$targetBaseUrl/$path" // 可扩展处理请求头、请求体,默认转发基础请求信息 return restTemplate.getForObject(targetUrl, Any::class.java) } } fun main(args: Array<String>) { runApplication<ProxyApplication>(*args) { setDefaultProperties(mapOf("server.port" to 9090)) } }
若需处理POST/PUT等请求,可添加对应
@RequestMapping方法,或不指定请求方法并补充请求体转发逻辑。
2. OkHttp 轻量代理(无容器依赖)
无需嵌入式容器,直接基于OkHttp实现HTTP服务器+转发逻辑,资源占用极低。
Kotlin示例
import okhttp3.OkHttpClient import okhttp3.Request import okhttp3.Response import okhttp3.HttpUrl.Companion.toHttpUrl import com.sun.net.httpserver.HttpServer import java.net.InetSocketAddress fun main() { val server = HttpServer.create(InetSocketAddress(9090), 0) val client = OkHttpClient() val targetBase = "http://localhost:5051".toHttpUrl() // 注册/my/path路径处理器 server.createContext("/my/path") { exchange -> val requestPath = exchange.requestURI.path.removePrefix("/my/path") val targetUrl = targetBase.newBuilder().encodedPath(requestPath).build() // 构建转发请求,保留原请求头和请求体 val forwardRequest = Request.Builder() .url(targetUrl) .method(exchange.requestMethod, exchange.requestBody.takeIf { it != -1 }?.let { okhttp3.RequestBody.create(null, exchange.requestBody) }) .apply { exchange.requestHeaders.forEach { key, values -> values.forEach { addHeader(key, it) } } } .build() // 发送请求并返回原始响应 client.newCall(forwardRequest).execute().use { response -> exchange.sendResponseHeaders(response.code, response.body?.contentLength() ?: -1) response.body?.byteStream()?.copyTo(exchange.responseBody) exchange.close() } } server.start() println("Proxy running on http://localhost:9090") }
3. Netty(高性能并发场景)
适合高并发请求场景,基于NIO实现,性能优于传统容器。
Java示例(简化版)
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.handler.codec.http.*; import java.net.URI; public class NettyProxyServer { private static final String TARGET_HOST = "localhost"; private static final int TARGET_PORT = 5051; private static final int PROXY_PORT = 9090; public static void main(String[] args) throws Exception { EventLoopGroup bossGroup = new NioEventLoopGroup(1); EventLoopGroup workerGroup = new NioEventLoopGroup(); try { ServerBootstrap b = new ServerBootstrap(); b.group(bossGroup, workerGroup) .channel(NioServerSocketChannel.class) .childHandler(new ChannelInitializer<SocketChannel>() { @Override public void initChannel(SocketChannel ch) { ChannelPipeline p = ch.pipeline(); p.addLast(new HttpRequestDecoder()); p.addLast(new HttpResponseEncoder()); p.addLast(new ProxyHandler()); } }); ChannelFuture f = b.bind(PROXY_PORT).sync(); f.channel().closeFuture().sync(); } finally { bossGroup.shutdownGracefully(); workerGroup.shutdownGracefully(); } } private static class ProxyHandler extends SimpleChannelInboundHandler<FullHttpRequest> { @Override protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest req) { // 移除/my/path前缀,拼接目标路径 String path = req.uri().replaceFirst("^/my/path", ""); URI targetUri = URI.create("http://" + TARGET_HOST + ":" + TARGET_PORT + path); // 构建客户端连接到目标服务器 Bootstrap clientBootstrap = new Bootstrap(); clientBootstrap.group(ctx.channel().eventLoop()) .channel(ctx.channel().getClass()) .handler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel ch) { ch.pipeline().addLast(new HttpResponseDecoder()); ch.pipeline().addLast(new HttpRequestEncoder()); ch.pipeline().addLast(new ClientHandler(ctx.channel())); } }); // 连接成功后转发请求 clientBootstrap.connect(TARGET_HOST, TARGET_PORT).addListener((ChannelFutureListener) future -> { if (future.isSuccess()) { future.channel().writeAndFlush(req.retain()); } else { ctx.channel().close(); } }); } } private static class ClientHandler extends SimpleChannelInboundHandler<FullHttpResponse> { private final Channel proxyChannel; public ClientHandler(Channel proxyChannel) { this.proxyChannel = proxyChannel; } @Override protected void channelRead0(ChannelHandlerContext ctx, FullHttpResponse resp) { // 将目标服务器的原始响应返回给JCEF浏览器 proxyChannel.writeAndFlush(resp.retain()); } @Override public void channelInactive(ChannelHandlerContext ctx) { proxyChannel.close(); } } }
4. Vert.x(响应式轻量方案)
基于事件驱动的响应式框架,资源占用低,适合嵌入式场景。
Kotlin示例
import io.vertx.core.Vertx import io.vertx.ext.web.Router import io.vertx.ext.web.client.WebClient fun main() { val vertx = Vertx.vertx() val client = WebClient.create(vertx) val router = Router.router(vertx) val targetBase = "http://localhost:5051" // 匹配所有/my/path下的请求 router.route("/my/path/*").handler { ctx -> val path = ctx.request().path().removePrefix("/my/path") val targetUrl = "$targetBase$path" // 转发请求,保留原请求头和请求体 client.request(ctx.request().method(), targetUrl) .putHeaders(ctx.request().headers()) .send(ctx.request().body()) .onSuccess { response -> ctx.response() .setStatusCode(response.statusCode()) .putHeaders(response.headers()) .end(response.body()) } .onFailure { ctx.response().setStatusCode(500).end("Proxy error") } } vertx.createHttpServer().requestHandler(router).listen(9090) { if (it.succeeded()) { println("Proxy running on http://localhost:9090") } } }
内容的提问来源于stack exchange,提问作者Shin938
相关产品推荐
相关产品推荐

