
今天我们正式引入API 网关。在微服务架构中网关是整个系统的统一入口负责请求路由、鉴权、限流、日志、聚合等横切关注点。今天我们将使用 Hyperf 从零搭建一个网关服务实现对后端用户服务、文章服务和订单服务的动态路由转发让客户端只需与网关交互而不再直接访问各个微服务。今日目标理解 API 网关在微服务架构中的核心价值与常见模式。创建独立的网关项目hyperf-gateway配置 HTTP 服务器。实现基础的请求转发网关接收请求根据路径前缀将请求透明地转发到对应的后端服务。实现动态路由将路由规则存储在配置中心Nacos支持运行时更改无需重启网关。测试网关转发功能验证客户端通过网关能正常访问文章、订单等接口并保持后端服务无感。一、环境准备创建网关项目约 30 分钟1. 创建新项目我们将网关作为独立的微服务项目与hyperf-app分离。进入容器并创建新项目docker-composeexecswoolebashcd/var/wwwcomposercreate-project hyperf/hyperf-skeleton hyperf-gateway等待安装完成进入项目cdhyperf-gateway2. 安装所需组件网关需要 HTTP 服务器、JSON-RPC 客户端用于转发不网关直接做 HTTP 代理即可但也可以集成 RPC。今天先实现 HTTP 反向代理、配置中心客户端。composerrequire hyperf/http-server hyperf/guzzle hyperf/config-nacoshyperf/guzzle是基于 Swoole 的协程 HTTP 客户端用于网关转发请求时发起后端调用。3. 配置基本环境编辑.env设置端口为9500避免与 9501 冲突APP_NAMEGateway APP_ENVdev APP_PORT9500确认config/autoload/server.php中 HTTP 服务监听0.0.0.0:9500。4. 配置 Nacos 连接创建config/autoload/config_center.php写入与之前相同的 Nacos 连接信息参考hyperf-app中的配置?phpreturn[driverHyperf\ConfigNacos\NacosDriver::class,client[hostnacos,port8848,usernamenacos,passwordnacos,],config[data_idgateway-routes,groupDEFAULT_GROUP,namespace_idenv(NACOS_NAMESPACE_ID,dev-001),typejson,],listener[enabletrue,interval3,],];在 Nacos 控制台的dev命名空间下新建配置gateway-routesJSON 格式内容暂时为空对象{}后续会填充路由规则。二、知识核心API 网关模式约 1 小时1. 为什么需要 API 网关在微服务架构中客户端直接访问各个微服务会带来诸多问题多入口前端需要记住多个域名/IP增加复杂度。横切逻辑重复每个服务都要处理鉴权、限流、日志等代码冗余。请求聚合不便移动端需要从多个服务拉取数据产生多次网络往返。安全性内部服务直接暴露攻击面增大。API 网关作为反向代理统一接收所有客户端请求然后转发到相应的后端服务并在此过程中插入公共逻辑。2. 网关的常见功能路由转发根据 URL、Header 等将请求映射到具体的后端服务。认证授权在网关层统一校验 JWT解析用户信息并传递给下游。限流熔断保护后端服务不被突发流量冲垮。日志与监控记录所有请求的元数据实现链路追踪的起点。协议转换对外暴露 HTTP/WebSocket对内可能调用 gRPC 或 JSON-RPC。聚合与裁剪将多个后端响应合并为一个减少客户端请求次数。3. 我们今天的实现方案网关独立的 Hyperf 项目监听9500内部使用Guzzle协程客户端向后端发起 HTTP 请求。路由配置存储在 Nacos 中格式例如{routes:[{prefix:/api/user,target:http://127.0.0.1:9502},{prefix:/api/order,target:http://127.0.0.1:9501}]}动态感知网关启动时加载路由规则并通过 Nacos 监听变更实时更新本地路由表。请求转发网关接收到请求后匹配最长路径前缀将请求的 URI、方法、Body、Header 透传到目标服务并将响应原样返回客户端。三、实战构建动态路由转发网关约 2.5 小时步骤 1创建路由管理服务新建app/Service/RouteService.php负责加载、缓存和匹配路由?phpnamespaceApp\Service;useHyperf\Contract\ConfigInterface;useHyperf\Di\Annotation\Inject;classRouteService{#[Inject]privateConfigInterface$config;privatearray$routes[];publicfunctionloadRoutes():void{// 从 Nacos 配置中心读取 routes 节点$this-routes$this-config-get(routes,[]);}/** * 根据请求URI匹配目标服务地址 */publicfunctionmatch(string$uri):?string{// 按前缀长度降序排序优先匹配更具体的路径$matchednull;$maxLength0;foreach($this-routesas$route){$prefix$route[prefix];if(str_starts_with($uri,$prefix)strlen($prefix)$maxLength){$maxLengthstrlen($prefix);$matched$route[target];}}return$matched;}}步骤 2网关核心中间件转发请求创建app/Middleware/GatewayMiddleware.php实现核心转发逻辑?phpnamespaceApp\Middleware;useApp\Service\RouteService;useHyperf\Di\Annotation\Inject;useHyperf\Guzzle\ClientFactory;usePsr\Http\Message\ResponseInterface;usePsr\Http\Message\ServerRequestInterface;usePsr\Http\Server\MiddlewareInterface;usePsr\Http\Server\RequestHandlerInterface;classGatewayMiddlewareimplementsMiddlewareInterface{#[Inject]privateRouteService$routeService;#[Inject]privateClientFactory$clientFactory;publicfunctionprocess(ServerRequestInterface$request,RequestHandlerInterface$handler):ResponseInterface{$uri$request-getUri()-getPath();$target$this-routeService-match($uri);if(!$target){// 未匹配路由返回 404return\Hyperf\Utils\ApplicationContext::getContainer()-get(\Hyperf\HttpServer\Contract\ResponseInterface::class)-json([code404,messageGateway: route not found])-withStatus(404);}// 构造目标 URL保留查询参数$query$request-getUri()-getQuery();$targetUrl$target.$uri.($query??.$query:);try{// 使用协程 Guzzle 客户端转发请求$client$this-clientFactory-create();$response$client-request($request-getMethod(),$targetUrl,[headers$request-getHeaders(),body(string)$request-getBody(),timeout5,// 超时时间]);// 将后端响应转换为 PSR-7 响应并返回return\Hyperf\Utils\ApplicationContext::getContainer()-get(\Hyperf\HttpServer\Contract\ResponseInterface::class)-withStatus($response-getStatusCode())-withBody(new\Hyperf\HttpMessage\Stream\SwooleStream($response-getBody()-getContents()))-withHeaders($response-getHeaders());}catch(\Throwable$e){// 转发失败返回 502 Bad Gatewayreturn\Hyperf\Utils\ApplicationContext::getContainer()-get(\Hyperf\HttpServer\Contract\ResponseInterface::class)-json([code502,messageGateway error: .$e-getMessage()])-withStatus(502);}}}步骤 3注册中间件并配置路由在config/autoload/middlewares.php中添加全局中间件?phpreturn[http[\App\Middleware\GatewayMiddleware::class,],];同时确保config/routes.php中没有任何特定路由因为所有请求都应该进入网关中间件进行转发。可以删除或保留默认的闭包路由网关中间件会拦截并处理。步骤 4配置 Nacos 路由规则打开 Nacos 控制台http://localhost:8848/nacos在dev命名空间下编辑gateway-routes写入{routes:[{prefix:/api/user,target:http://hyperf-app:9502},{prefix:/api/product,target:http://hyperf-app:9504},{prefix:/articles,target:http://hyperf-app:9501},{prefix:/orders,target:http://hyperf-app:9501},{prefix:/auth,target:http://hyperf-app:9501}]}注意因为网关和hyperf-app在同一个 Docker 网络中可以使用容器名hyperf-app需确认 Docker Compose 中服务名或者直接用127.0.0.1但推荐容器名。如果服务都在宿主机网络可以用host.docker.internal或127.0.0.1。步骤 5启动网关并测试转发启动网关服务端口 9500php bin/hyperf.php start测试通过网关访问文章列表curlhttp://localhost:9500/articles应返回文章列表数据来自hyperf-app:9501。测试订单详情curlhttp://localhost:9500/orders/1应返回聚合订单数据包括用户和商品信息内部 RPC 调用仍然在hyperf-app内完成。测试用户服务直接通过网关curl-XPOST http://localhost:9500/api/user-HContent-Type: application/json-d{jsonrpc:2.0,method:user/GetUserById,params:[1],id:1}注意用户服务原本是 JSON-RPC 接口但网关目前透明转发 HTTP所以只要路径前缀匹配网关就会转发请求到9502的 JSON-RPC 处理器因此能正常工作。验证动态路由在 Nacos 中修改gateway-routes添加一个前缀/test指向http://hyperf-app:9501发布。稍等几秒访问curl http://localhost:9500/test预期能到达hyperf-app的默认路由可能 404但说明网关已加载新路由。无需重启网关。四、成果测试与验证约 1 小时1. 测试清单检验项方法通过标准网关启动并监听curl http://localhost:9500无路由时返回 404网关响应状态码 404 由网关生成路由匹配成功curl http://localhost:9500/articles返回文章列表与直接访问 9501 一致路径前缀匹配新增路由/orders指向 9501能正确获取订单不存在的路由curl http://localhost:9500/nonexist返回 404由网关提供动态添加路由在 Nacos 新增路由等待后访问新路由生效无需重启后端服务故障暂时停止 9501 服务访问/articles返回 502网关提示错误请求方法透传curl -X POST http://localhost:9500/auth/login ...正常登录说明 POST 和 Body 正确转发查询参数透传curl http://localhost:9500/articles?page1分页参数生效2. 常见问题与调试无法连接后端检查网关能否解析hyperf-app容器名可在网关容器内ping hyperf-app或直接用 IP。路由不生效检查 Nacos 连接配置确认gateway-routes的 Data ID 正确观察网关日志是否有配置更新。Guzzle 超时后端处理慢可能导致超时调整timeout参数并考虑异步化或增加重试。3. 性能初探网关增加了一层网络转发延迟会略微上升。通过ab对比直连和网关访问的响应时间可以看到网关引入的延迟在毫秒级但带来的架构收益巨大。五、今日作业与学习产出提交代码将hyperf-gateway项目提交到 Git包括GatewayMiddleware、RouteService、配置等。增强网关为网关添加请求日志中间件记录每个请求的方法、路径、状态码和耗时。实现请求重试转发失败时尝试重试一次适用于幂等 GET 请求。学习笔记画出网关在微服务架构中的位置图标出数据流。对比 API 网关与反向代理Nginx的异同思考为什么需要应用层网关。挑战任务研究 Hyperf 的协程 HTTP 客户端了解hyperf/guzzle的连接池配置优化网关并发性能。实现基于请求头的路由如X-Group: v2实现更灵活的灰度分流。通过今天的学习你已经成功构建了一个灵活、可动态配置的 API 网关为整个微服务系统提供了统一入口。明天我们将为网关加上全局 JWT 鉴权并实现向下游服务透传用户信息。