响应
ACE 提供多种方式设置响应内容。所有方式均通过 Context(ctx)对象操作,在中间件或控制器方法中均可使用。
直接返回响应体
返回字符串
控制器方法返回 String 时,框架自动将其写入响应体,并将 Content-Type 设置为 text/plain; charset=utf-8。
cangjie
@Controller["/hello"]
class HelloController {
@Get[""]
func index(): String {
return "Hello, ACE!"
}
}返回 JSON 结构体
实现 toJson(): String 方法的 struct 或 class,框架自动将其序列化为 JSON,并将 Content-Type 设置为 application/json; charset=utf-8。
cangjie
struct UserVO {
let id: Int64
let name: String
func toJson(): String {
return """{"id":${id},"name":"${name}"}"""
}
}
@Controller["/users"]
class UserController {
@Get["/:id"]
func getUser(@PathParam id: Int64): UserVO {
return UserVO(id: id, name: "Alice")
}
}手动操作 ctx
设置响应体
cangjie
// 设置纯文本体
ctx.body = "操作成功"
// 手动设置 JSON 体(同时更新 Content-Type)
ctx.json("""{"code":0,"msg":"ok"}""")设置状态码
cangjie
ctx.status = 201u16 // Created
ctx.status = 204u16 // No Content
ctx.status = 404u16 // Not FoundTIP
仓颉中整数字面量需要显式后缀,状态码必须写 u16,否则类型不匹配。
设置响应头
cangjie
ctx.setHeader("X-Request-Id", "abc-123")
ctx.setHeader("Cache-Control", "no-cache")设置 Cookie
cangjie
import ace_web.CookieOptions
let opts = CookieOptions(
httpOnly: true,
maxAge: 86400, // 秒
path: "/",
secure: true
)
ctx.setCookie("session", "tok_xyz", opts)CookieOptions 字段说明
| 字段 | 类型 | 默认值 | 说明 |
|---|---|---|---|
httpOnly | Bool | false | 禁止 JavaScript 访问 |
maxAge | Int64 | 0(会话) | Cookie 有效期(秒) |
path | String | "/" | Cookie 作用路径 |
secure | Bool | false | 仅 HTTPS 发送 |
sameSite | String | "" | Strict/Lax/None |
domain | String | "" | Cookie 作用域名 |
流式响应
对于大文件下载、SSE 等场景,使用 ctx.setStreamBody 进行分块传输(Transfer-Encoding: chunked)。
cangjie
@Get["/events"]
func sse(ctx: Context): Unit {
ctx.setHeader("Content-Type", "text/event-stream")
ctx.setHeader("Cache-Control", "no-cache")
ctx.setStreamBody { write in
for i in 0..5 {
write("data: message ${i}\n\n")
// 实际场景中可在此 await 异步数据源
}
}
}WARNING
setStreamBody 闭包执行期间不可再设置响应头或状态码,请在调用前完成所有头部配置。
内容协商
ACE 支持按请求 Accept 头自动选择编码器。通过 registerBodyEncoder 注册自定义格式:
cangjie
import ace_web.{registerBodyEncoder, BodyEncoder}
// 注册 MessagePack 编码器(示例)
registerBodyEncoder("application/msgpack", MsgpackEncoder())
// encodeBody 根据 Accept 头自动选择
@Get["/data"]
func getData(ctx: Context): MyData {
return encodeBody(ctx, MyData(...))
}registerBodyEncoder 参数:
| 参数 | 类型 | 说明 |
|---|---|---|
mimeType | String | 对应 Accept 头值 |
encoder | BodyEncoder | 实现 encode(Any): String 的编码器实例 |
gzip 压缩
在 App 中挂载 gzipMiddleware 即可对响应体自动压缩:
cangjie
import ace_web.App
import ace_framework.middleware.gzipMiddleware
let app = App()
app.use(gzipMiddleware(minLength: 1024)) // 超过 1KB 才压缩TIP
gzipMiddleware 仅压缩 text/* 和 application/json,二进制流不会被二次压缩。