响应与渲染
InternalWebServer.buildResult 把 Action 结果转换为 HTTP Response,顺序是:Render → 模板 → 空值状态码 → 类型分派。
普通对象与 String
普通对象经 FastJSON2 序列化为 application/json:
@GetAction("{id}")
fun user(id: Long): UserDto = userService.get(id)String 根据开头猜测类型:{/[ 为 JSON,<?xml 为 XML,< 为 HTML,其他为纯文本。这是启发式规则;需要稳定媒体类型时使用 Render 或直接设置 Response。
空返回值
结果为 null 且状态仍是 200 时:POST 返回 201,其他方法返回 204。需要 404、带 Location 的 201 等语义必须显式渲染。
二进制、流与文件
支持直接返回:
Byte/ByteArrayInputStreamUploadFileFileDownloadFile
File/UploadFile 根据扩展名推断 Content-Type;未知类型使用 application/octet-stream 并添加 filename。文件名进入 Header 前应过滤换行和危险字符。
Response API
fun custom(response: Response) {
response.status = 202
response.contentType = "text/plain"
response.addHeader("X-Request-Id", requestId)
response.addCookie("theme", "dark")
response.write("accepted".toByteArray())
}主动写出后不要再返回普通结果,避免二次写入。
Response 还提供 charset、contentLength、headers、cookies、output,以及 ByteArray/InputStream 写入入口。具体 header 提交时机由服务器实现决定。
Render
fun interface Render {
operator fun invoke(context: WebActionContext, server: InternalWebServer): Any?
}返回 null 表示已经处理完成;非 null 会递归交给 buildResult:
fun accepted(body: Any) = Render { context, _ ->
context.resp.status = 202
body
}Render.render() 抛出 ActionResult,可从 Before/Action 立即中止流程:
fun requireLogin(user: IUser?) {
if (user == null) render401("login required")
}内置 render302、render401、render403。
统一 API 响应
建议项目封装状态码和错误结构:
data class ApiError(val code: String, val message: String?)
fun apiError(status: Int, error: ApiError) = Render { context, _ ->
context.resp.status = status
error
}再由 Catch 使用。这样避免每个 Action 直接操作 Response,也绕开 String 类型猜测。
模板
SmartWeb 可按 Controller 与 Action 名称发现服务端模板。存在 Temple 且请求 Accept 首项是 text/html 时,模板优先于普通返回值渲染。
模板路径、变量传递、Rythm 资源目录、自定义 TempleEngine 以及当前尚未接通的生命周期限制,见模板引擎。
500 错误
未被 Catch 处理的异常变成 500。开发模式会把 stack trace 转成 HTML 风格内容,生产模式不应暴露。领域异常应通过 Catch + 统一 Render 转换。
与 Spring MVC 对照
Spring MVC 使用 ReturnValueHandler、HttpMessageConverter、ViewResolver 和内容协商;SmartWeb 用一个 when(result) 加 Render/Temple 两个扩展出口。实现清晰但缺少成熟 Accept 协商、编码器注册、Range、ETag 和流式响应。公共 API 应在项目层封装统一 Render。