3

我想实现一个http4s服务器,它从另一个服务接收内容,处理它并返回响应。

原始服务使用重定向,所以我添加了Follow 重定向中间件。我还添加了 Logger 中间件来检查生成的日志。

服务的骨架是:

implicit val clientResource = BlazeClientBuilder[F](global).resource
val wikidataEntityUrl = "http://www.wikidata.org/entity/Q"

def routes(implicit timer: Timer[F]): HttpRoutes[F] = HttpRoutes.of[F] {
 case GET -> Root / "e" / entity => {
   val uri =  uri"http://www.wikidata.org/entity/" / ("Q" + entity)
   val req: Request[F] = Request(uri = uri)
   clientResource.use { c => {
     val req: Request[F] = Request(Method.GET, uri)
     def cb(resp: Response[F]): F[Response[F]] = Ok(resp.bodyAsText)
     val redirectClient = Logger(true,true,_ => false)(FollowRedirect[F](10, _ => true)(c))
     redirectClient.fetch[Response[F]](req)(cb)
 }}}}

当我尝试使用 curl 访问服务时:

curl -v http://localhost:8080/e/33

响应包含原始内容的第一部分,并以:

transfer closed with outstanding read data remaining
* Closing connection 0

查看日志,它们包含以下行:

ERROR o.h.s.blaze.Http1ServerStage$$anon$1 - Error writing body
org.http4s.InvalidBodyException: Received premature EOF.

这表明接收过早的 EOF 时出错。

我在这个问题上找到了一个可能的答案:但答案建议使用不推荐使用的方法,如 tohttpService。

我想我需要使用流重写代码,但我不确定更惯用的方法是什么。一些建议?

4

1 回答 1

3

我在 http4s gitter 频道中得到了一些帮助来使用toHttpApp方法而不是fetch方法。

还建议我将客户端作为参数传递。

结果代码是:

 case GET -> Root / "s" / entity => {
  val uri =  uri"http://www.wikidata.org/entity/" / ("Q" + entity)
  val req: Request[F] = Request(Method.GET, uri)
  val redirectClient = Logger(true,true,_ => false)(FollowRedirect[F](10, _ => true)(client))
  redirectClient.toHttpApp.run(req)
}

现在它按预期工作。

toHttpApp方法旨在用于代理服务器。

于 2019-08-06T07:10:57.680 回答