侧边栏壁纸
博主头像
colo

欲买桂花同载酒

  • 累计撰写 1823 篇文章
  • 累计收到 0 条评论

设计一个简单的Akka HTTP路由,实现GET和POST请求处理

2025-12-8 / 0 评论 / 4 阅读

题目

设计一个简单的Akka HTTP路由,实现GET和POST请求处理

信息

  • 类型:问答
  • 难度:⭐⭐

考点

Akka HTTP路由定义, 请求处理, 序列化/反序列化

快速回答

实现一个包含以下功能的路由:

  • GET /items 返回所有物品的JSON列表
  • POST /items 接收JSON格式的新物品并返回创建状态
  • 使用case class表示数据模型
  • 处理JSON序列化/反序列化
## 解析

核心实现步骤

以下是一个完整的Akka HTTP路由实现:

import akka.actor.typed.ActorSystem
import akka.actor.typed.scaladsl.Behaviors
import akka.http.scaladsl.server.Directives._
import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport._
import spray.json.DefaultJsonProtocol._

// 1. 定义数据模型和JSON格式
case class Item(id: Int, name: String, price: Double)

object JsonFormats {
  implicit val itemFormat = jsonFormat3(Item)
}

// 2. 创建路由
class ItemRoutes {
  import JsonFormats._

  // 模拟数据存储
  private var items = Vector(
    Item(1, "Keyboard", 29.99),
    Item(2, "Mouse", 19.95)
  )

  val routes = 
    pathPrefix("items") {
      concat(
        // GET /items 返回所有物品
        get {
          complete(items)
        },
        // POST /items 创建新物品
        post {
          entity(as[Item]) { item =>
            items :+= item.copy(id = items.size + 1) // 模拟ID生成
            complete(s"Item ${item.name} created")
          }
        }
      )
    }
}

// 3. 启动HTTP服务器
object Main extends App {
  implicit val system = ActorSystem(Behaviors.empty, "AkkaHTTPExample")

  val routes = new ItemRoutes().routes

  val bindingFuture = Http().newServerAt("localhost", 8080).bind(routes)
  println(s"Server online at http://localhost:8080/")
}

原理说明

  • 路由结构:使用Akka HTTP的DSL构建路由树,pathPrefix定义公共路径,concat组合多个路由
  • JSON处理:通过Spray JSON实现自动序列化(complete(items))和反序列化(entity(as[Item]))
  • 幂等性处理:POST请求中copy(id = ...)确保服务端控制ID生成,避免客户端重复提交问题

最佳实践

  • 分离关注点:路由定义、JSON格式、业务逻辑分层组织
  • 错误处理:实际项目中应添加异常处理,例如:
    handleExceptions(ExceptionHandler {
      case _: IllegalArgumentException => 
        complete(StatusCodes.BadRequest, "Invalid data")
    })
  • 状态码规范:POST成功应返回201 Created,示例中可添加:
    complete(StatusCodes.Created, ...)

常见错误

  • JSON格式不匹配:case class字段与JSON字段不一致导致解析失败
  • 线程安全问题:示例中var items非线程安全,生产环境需使用Actor或持久化存储
  • 缺少内容协商:未指定Content-Type头可能导致客户端解析错误,应显式指定:
    post {
      entity(as[Item]) { ... }
    }

扩展知识

  • 路由测试:使用Akka HTTP TestKit编写单元测试
  • 依赖注入:结合MacWire或Guice管理路由依赖
  • 流式处理:对于大文件上传/下载,可使用Akka Streams集成
  • CQRS模式:复杂场景可将读写操作分离到不同路由