wastnet 反向代理实战:用一个端口统一托管前端与后端 API

2026-09-01 25 预计阅读时间: 1 分钟
来源: oschina.net AI 摘要 Original link

Disclaimer: This article is an AI-assisted summary. Read it together with the original source when precision matters. The summary may omit context, version differences, or edge cases and is not official documentation.

预计阅读时间:10 分钟

前端静态资源和后端 API 分别监听不同端口,是开发阶段常见的部署方式:前端可能运行在 3000,Java API 运行在 8080。但到了测试或生产环境,用户通常只希望访问一个域名和一个端口。wastnet 的反向代理能力可以把这两类请求统一接入,再按路径转发到不同的后端服务。

wastnet 是一款零依赖、自研的 Java Web 服务器,核心基于 JDK 原生 NIO 构建 Reactor 多路复用模型,不依赖 Netty、Tomcat 等第三方网络库。它还自研了 HTTP/2 的 HPACK、Huffman 和 ALPN 协议栈,支持 h2h2c。本文重点放在实际部署模型:如何让一个监听端口同时提供前端页面和后端 API。

统一入口的请求模型

可以把请求分成两类:

  • /api/*:转发到后端 Java 服务,例如 127.0.0.1:8080
  • 其他路径:由 wastnet 直接读取前端构建目录,例如 /srv/www/app

请求路径经过统一入口后,浏览器不再需要感知后端端口:

浏览器
   |
   |  http://example.com:8080
   v
wastnet
   |-- /api/users   -> http://127.0.0.1:9000/users
   |-- /api/login   -> http://127.0.0.1:9000/login
   `-- /assets/*、/ -> /srv/www/app

这里的端口只是示例。生产环境可以让 wastnet 监听 80443,后端服务只绑定到本机回环地址,避免直接暴露 API 端口。

这种路由方式有三个直接收益:

  1. 前端请求使用相对路径,例如 fetch('/api/users'),不需要把后端地址写进构建产物。
  2. 浏览器访问同一个源,开发和部署时的跨域配置更简单。
  3. 后端服务可以独立重启、扩容或迁移,外部入口保持不变。

一个可改造的部署配置

摘要没有给出 wastnet 的固定配置文件格式,因此下面示例采用“等价配置”的形式,字段名需要按照实际版本的配置 API 或启动参数调整。它表达的是可落地的路由规则,而不是声称某个版本一定支持这些原始字段。

server:
  host: 0.0.0.0
  port: 8080

static:
  root: /srv/www/app
  index: index.html
  spa_fallback: /index.html

proxy:
  - match: /api/
    target: http://127.0.0.1:9000
    strip_prefix: /api
    preserve_host: true
    timeout_ms: 10000

其中 strip_prefix 决定后端收到的路径。如果浏览器请求 /api/users,开启后后端收到的是 /users;如果后端路由本身包含 /api,则应关闭此前缀剥离,避免路径重复。

如果 wastnet 使用 Java API 注册路由,可以按下面的伪代码组织配置。实际类名和方法名应以项目版本为准:

public final class GatewayConfig {
    public static void configure(Server server) {
        server.listen("0.0.0.0", 8080);

        server.proxy("/api/", ProxyTarget.http("http://127.0.0.1:9000")
                .stripPrefix("/api")
                .preserveHost(true)
                .connectTimeoutMillis(2000)
                .readTimeoutMillis(10000));

        server.staticFiles("/srv/www/app")
                .index("index.html")
                .spaFallback("/index.html");
    }
}

启动前准备一个最小的前端目录:

sudo mkdir -p /srv/www/app
printf '<!doctype html><html><body><h1>wastnet app</h1></body></html>\n' \
  | sudo tee /srv/www/app/index.html >/dev/null

# 后端服务示例:实际项目应替换为自己的启动命令
java -jar backend.jar --server.port=9000

# 再启动 wastnet;参数名称按实际版本调整
java -jar wastnet.jar --config /etc/wastnet/app.yml

启动后可以分别检查静态资源和代理链路:

curl -i http://127.0.0.1:8080/
curl -i http://127.0.0.1:8080/api/health

如果 API 后端提供的是 /health,而代理规则剥离了 /api,第二个请求最终会访问后端的 /health

前端路由、请求头与失败处理

单页应用通常需要处理浏览器直接访问 /dashboard 的情况。服务器找不到名为 dashboard 的物理文件时,应回退到 index.html,再由前端路由接管。这个回退规则只适用于页面请求,不应把 API 的 404 也回退成 HTML,否则前端会收到状态码正确但内容类型错误的响应。

反向代理还需要明确处理请求头。至少应关注以下信息:

  • Host:是否保留客户端访问的域名。
  • X-Forwarded-For:记录真实客户端地址,后端日志和限流通常会用到。
  • X-Forwarded-Proto:告诉后端外部请求是 HTTP 还是 HTTPS。
  • Content-LengthTransfer-Encoding:转发请求体时必须保持协议语义一致。

可以在后端服务中按类似方式读取代理头,但只有在代理层可信时才应相信这些值:

String clientIp = request.getHeader("X-Forwarded-For");
if (clientIp == null || clientIp.isBlank()) {
    clientIp = request.getRemoteAddr();
}

String scheme = request.getHeader("X-Forwarded-Proto");
if (scheme == null || scheme.isBlank()) {
    scheme = request.getScheme();
}

生产环境还要为上游不可用设计清晰的行为。后端连接失败时,代理应返回 502 Bad Gateway;读取超时应返回 504 Gateway Timeout,并记录上游地址、请求路径和耗时。不要把所有代理错误都伪装成前端 index.html,否则排查问题时很难区分页面不存在和 API 服务故障。

HTTP/2 与部署边界

wastnet 的 HTTP/2 能力覆盖 h2h2c,并且协议栈中的 HPACK、Huffman 和 ALPN 由项目自行实现。对于浏览器生产访问,通常会使用 TLS 加密的 h2h2c 更适合受控的内网或调试场景,不能简单等同于面向公网的 HTTPS 部署。

可以这样验证客户端实际使用的协议:

curl -vk --http2 https://example.com/
curl -v --http1.1 http://127.0.0.1:8080/api/health

是否启用 HTTP/2、TLS 证书如何配置、代理是否支持 WebSocket 或流式响应,都应以当前 wastnet 版本的文档和 API 为准。HTTP/2 不会自动解决后端慢查询、连接池不足或大响应缓冲等问题;它主要改变客户端与入口服务器之间的传输方式。

上线前检查清单

部署这个模式时,可以逐项确认:

  • wastnet 的监听地址和端口已确定,防火墙只开放统一入口。
  • 后端 API 只绑定 127.0.0.1 或受控内网地址。
  • /api/ 的路径是否需要剥离前缀已经和后端路由对齐。
  • 前端 SPA 回退不会吞掉 API 的 404502504
  • 静态资源启用了缓存策略,HTML 入口文件保留较短缓存时间。
  • 代理超时、最大请求体、上传文件大小和连接数限制符合业务需求。
  • 日志同时记录入口请求、上游状态、响应耗时和关联请求 ID。
  • 在启用 HTTP/2 或 TLS 后,使用 curl 和浏览器开发者工具确认协商结果。

一个端口统一托管前端和 API,真正的价值不只是减少端口数量,而是把浏览器看到的访问边界固定下来。wastnet 的零依赖 NIO 架构和自研 HTTP/2 协议栈适合希望控制服务器组成的 Java 项目;但落地时仍应以实际版本的配置能力、压测数据和故障行为为依据,逐步验证静态文件、代理请求、超时和协议协商这几条关键链路。


相关推荐