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

Play Framework端点如何获取RequestContext?兼容Pekko extractRequestContext

迁移Akka REST到Play 3.0的两个关键问题解决

1. 替代Pekko extractRequestContext获取请求上下文

Play框架中没有直接对应Pekko HTTP的RequestContext类型,但Action参数中的Request对象已经包含了所有请求上下文相关信息:

  • 请求头:request.headers
  • 客户端地址:request.remoteAddress
  • 请求ID:request.id
  • 自定义属性:request.attrs(用于存储请求级别的自定义数据)

如果原代码中extractRequestContext是为了提取用户标识(userKey)这类数据,可通过Play的请求属性、Session或Headers直接获取,无需额外提取上下文对象。例如:

// 假设userKey存储在请求属性中
val userKey = request.attrs(Attrs.UserKey)

2. 将Play文件转换为StrictForm.FileData

要把Play的MultipartFormData.FilePart转换为依赖库要求的StrictForm.FileData,需根据FileData的构造逻辑手动映射字段,以下是通用转换方案:

步骤1:明确StrictForm.FileData的结构

通常StrictForm.FileData包含三个核心字段:

  • 文件名(filename: String)
  • 内容类型(contentType: Option[String])
  • 数据流(source: Source[ByteString, _])

步骤2:编写转换逻辑

在Action中处理文件上传时,直接从FilePart提取字段并构造FileData:

import org.apache.pekko.stream.scaladsl.Source
import org.apache.pekko.util.ByteString
import java.nio.file.Files

def createWorkspace = Action(parse.multipartFormData) { implicit request =>
  // 转换Play文件为StrictForm.FileData
  val maybeIcon = request.body.file("icon").map { picture =>
    StrictForm.FileData(
      filename = picture.filename,
      contentType = picture.contentType,
      // 从临时文件读取字节流构造Source
      source = Source.single(ByteString(Files.readAllBytes(picture.ref.path)))
    )
  }

  // 绑定表单其他字段(排除icon,后续合并)
  workspaceForm.bindFromRequest.fold(
    errors => {
      println(errors.toString())
      BadRequest("Ooops")
    },
    baseRequest => {
      // 合并icon字段到请求对象
      val fullRequest = baseRequest.copy(icon = maybeIcon)
      onboardingController.saveData(fullRequest)
      Ok("")
    }
  )
}

步骤3:调整表单定义

如果原workspaceForm包含icon字段,需修改为只绑定非文件字段,后续手动合并:

import play.api.data.Form
import play.api.data.Forms._

case class WorkspaceRequest(
  name: String,
  description: Option[String],
  icon: Option[StrictForm.FileData],
  color: String
)

val workspaceForm = Form(
  mapping(
    "name" -> nonEmptyText,
    "description" -> optional(text),
    "color" -> nonEmptyText
  )((name, desc, color) => WorkspaceRequest(name, desc, None, color))(
    wr => Some((wr.name, wr.description, wr.color))
  )
)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 05:43:18