使用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());
}
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 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)