如何将使用自定义指令的Akka HTTP路由迁移至http4s
http4s 实现等效Akka HTTP请求头替换逻辑方案
核心逻辑说明
http4s 中Request为不可变值,和Akka HTTP的mapRequest处理逻辑兼容:不需要单独提取修改后的Headers集合,直接基于原请求生成携带新请求头的完整Request实例即可。要实现类似Akka自定义指令包裹路由、内部逻辑无感知获取处理后请求的效果,可根据场景选择以下两种实现:
方案1:单路由轻量实现
调整原replaceHeaders方法,直接返回修改后的完整请求对象,路由内后续所有解析、业务逻辑都基于该修改后的对象执行即可,代码如下:
import org.http4s._ import org.http4s.dsl.io._ import cats.effect.IO import org.typelevel.ci.CIString // 直接返回修改后的完整Request,而非单独的Headers集合 def replaceHeaders(originalReq: Request[IO]): Request[IO] = { val searchHeaderName = CIString("SomeHeader") val newHeaderName = CIString("NewHeader") originalReq.headers.get(searchHeaderName) match { case Some(targetHeader) => originalReq.withHeaders( originalReq.headers .filterNot(_.name == searchHeaderName) .put(Header.Raw(newHeaderName, targetHeader.value)) ) case None => originalReq } } // 对应Akka逻辑中的SomeData样例类,按实际业务定义字段 case class SomeData(testField: String) val singleRoute: HttpRoutes[IO] = HttpRoutes.of[IO] { case rawReq @ POST -> Root => // 生成经过头替换处理的请求对象 val modifiedReq = replaceHeaders(rawReq) // 从修改后的请求解析请求体,等效Akka的entity(as[SomeData]) modifiedReq.as[SomeData].flatMap { someData => // 此处访问modifiedReq即可直接获取替换后的请求头,无需额外传值 // 编写实际业务逻辑 Ok("Process ok.") } }
方案2:中间件实现可复用指令(完全等效Akka自定义Directive)
如果需要将头替换逻辑复用到多个路由,实现类似Akka指令包裹整段路由的效果,可以使用http4s原生的中间件机制。中间件本质是对路由的包裹函数,会统一对进入包裹范围的请求做预处理,下层路由直接拿到处理后的请求对象,无需重复编写处理逻辑,代码如下:
import cats.data.Kleisli // 定义可复用的头替换中间件,用法和Akka的replaceHeaders指令完全一致 def replaceHeadersMiddleware(routes: HttpRoutes[IO]): HttpRoutes[IO] = Kleisli { rawReq => val modifiedReq = replaceHeaders(rawReq) // 将修改后的请求传递给下层路由 routes(modifiedReq) } // 用中间件包裹整段路由,内部所有端点自动应用头替换逻辑 val wrappedRoutes: HttpRoutes[IO] = replaceHeadersMiddleware { HttpRoutes.of[IO] { // 此处匹配到的req已经完成头替换,无需手动调用replaceHeaders case req @ POST -> Root => req.as[SomeData].flatMap { someData => // 直接访问req.headers即可拿到替换后的新请求头 Ok("Process ok.") } // 同包裹范围内的其他路由自动继承预处理逻辑 case req @ GET -> Root / "health" => Ok("healthy") } }
注意:http4s的请求、响应对象均为不可变类型,
withHeaders这类修改方法会返回新的对象实例,不会修改原始请求,行为和Akka HTTP的请求处理逻辑完全一致。使用中间件包裹后,下层路由完全感知不到预处理逻辑的存在,和Akka自定义指令的开发体验完全对等。
内容的提问来源于stack exchange,提问作者M.G.
相关产品推荐
相关产品推荐

