You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Akka Http调用Bing Search API后如何改写响应并转发?

你的方案可行性分析与修复方案

你的核心思路(调用Bing Search API → 获取响应体 → 解析JSON并添加额外字段 → 返回给客户端)完全可行,只是代码里存在异步流程嵌套混乱、JSON操作不完整、错误处理缺失等细节问题,导致无法正常运行。下面是具体的修复步骤和优化后的代码:

核心问题拆解

  1. 异步流程嵌套地狱:你把toStrict、runFold、map多层嵌套,导致类型推断混乱,代码可读性极差,也容易出现异步流处理错误。
  2. 冗余的流处理:toStrict已经将Akka HTTP的流式实体转换成完整的StrictEntity,不需要再用runFold手动累加字节流。
  3. Circe JSON操作不完整:withFocus返回的是ACursor类型,需要提取最终的Json值,同时要处理修改失败的情况(比如原始JSON不是对象)。
  4. 错误处理缺失:没有处理Bing API请求失败、JSON解析失败、实体转换超时等异常场景,会导致路由抛出未处理的异常。
  5. 响应类型不匹配:complete需要的是符合ToResponseMarshallable的类型,你的代码返回的嵌套Future无法被正确识别。

修复后的完整代码

首先确保引入必要的依赖(以sbt为例):

libraryDependencies ++= Seq(
  "com.typesafe.akka" %% "akka-http" % "10.2.9",
  "io.circe" %% "circe-core" % "0.14.1",
  "io.circe" %% "circe-generic" % "0.14.1",
  "io.circe" %% "circe-parser" % "0.14.1",
  "io.circe" %% "circe-akka-http" % "0.14.1" // 用于自动将Circe Json转为Akka HTTP响应
)

优化后的路由代码

import akka.actor.ActorSystem
import akka.http.scaladsl.Http
import akka.http.scaladsl.model.{HttpRequest, RawHeader, StatusCodes}
import akka.http.scaladsl.server.Directives._
import akka.stream.Materializer
import io.circe._
import io.circe.generic.auto._
import io.circe.parser._
import io.circe.syntax._
import io.circe.akka.http._
import scala.concurrent.{ExecutionContext, Future}
import scala.concurrent.duration._
import java.net.URLEncoder

// 假设q是从路由提取的查询参数,k1是你的Bing API密钥
def bingSearchRoute(q: String, k1: String)(implicit system: ActorSystem, mat: Materializer, ec: ExecutionContext) = {
  // 准备要添加的额外数据
  val extraData = Map("key1" -> "value1", "key2" -> "val2").asJson
  // 编码查询参数,避免URL非法字符
  val encodedQuery = URLEncoder.encode(q, "UTF-8")
  val bingApiUri = s"https://api.cognitive.microsoft.com/bing/v7.0/search?q=$encodedQuery"

  // 构建完整的异步处理流程
  val modifiedResponseFuture: Future[Json] = Http().singleRequest(
    HttpRequest(uri = bingApiUri)
      .withHeaders(RawHeader("Ocp-Apim-Subscription-Key", k1))
  ).flatMap { originalResponse =>
    // 先检查Bing API的响应状态是否成功
    if (originalResponse.status.isSuccess()) {
      // 将流式实体转为完整的StrictEntity,超时时间2秒
      originalResponse.entity.toStrict(2.seconds).map { strictEntity =>
        // 解析原始JSON响应
        parse(strictEntity.data.utf8String) match {
          case Left(parseError) =>
            // 解析失败时返回错误JSON
            Json.obj("error" -> Json.fromString(s"Failed to parse Bing response: ${parseError.message}"))
          case Right(originalJson) =>
            // 向原始JSON对象添加额外字段
            originalJson.hcursor
              .withFocus(_.mapObject(_.add("extraData", extraData)))
              .top // 获取修改后的Json,若修改失败(如原始不是对象)则返回None
              .getOrElse(originalJson) // 降级处理:修改失败则返回原始JSON
        }
      }
    } else {
      // Bing API返回错误状态,抛出异常后续由recover处理
      Future.failed(new RuntimeException(s"Bing API returned error: ${originalResponse.status}"))
    }
  }.recover {
    // 处理超时异常
    case _: akka.stream.impl.StreamTimeoutException =>
      Json.obj("error" -> Json.fromString("Request to Bing API timed out"))
    // 处理其他所有异常
    case e: Exception =>
      Json.obj("error" -> Json.fromString(s"Unexpected error: ${e.getMessage}"))
  }

  // 直接返回Future[Json],circe-akka-http会自动转为HttpResponse
  complete(modifiedResponseFuture)
}

关键优化点说明

  1. 异步流程扁平化:用链式flatMap替代多层嵌套,让异步逻辑更清晰,类型推断更准确。
  2. 简化实体读取:利用toStrict直接获取完整的响应体字节串,省去冗余的流累加操作。
  3. Circe JSON操作完善:用.top.getOrElse(originalJson)处理JSON修改失败的场景,避免崩溃。
  4. 全链路错误处理:覆盖了API请求失败、JSON解析失败、超时等所有异常场景,返回友好的错误响应。
  5. 自动响应转换:借助circe-akka-http的自动marshaller,直接返回Future[Json]即可,无需手动构建HttpResponse。

内容的提问来源于stack exchange,提问作者RB_

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 07:57:37