使用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());
}
}
}

浙公网安备 33010602011771号