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

如何为Plumber API指定带JSON类型的非默认响应状态码?

问题

我基于注解风格构建Plumber API,想指定除默认200“OK”和500“内部服务器错误”之外的响应状态码,且这些错误响应的Content-Type为application/json(而非text/html)。参考结构化错误处理逻辑实现后,示例路由原本运行正常,但添加@response注解后,生成的OpenAPI规范中403、404响应并未设置为期望的application/json类型(默认500错误的Content-Type却是正确的)。

原正常路由代码:

# Define the Plumber API using annotations
#* @get /predict/<file_id>
#* @param file_id:string ID or name of the RDS file
#* @serializer html

function(res, req, file_id) {
  future::future({
    loaded_model <- list()
        loaded_model <- find_or_download_model(file_id, env_var$model_local_dir, 
        env_var$model_s3_bucket, env_var$model_s3_endpoint, env_var$s3_accesskey, 
        env_var$s3_secretkey)

    return("Success, File Found.")
  })
}

添加@response注解后的路由:

# Define the Plumber API using annotations
#* @get /predict/<file_id>
#* @param file_id:string ID or name of the RDS file
#* @serializer html
#* @response 403 Forbidden <== HERE
#* @response 404 Not Found   <== AND HERE

修复方案

1. 明确指定@response的内容类型

Plumber的@response注解支持直接嵌入OpenAPI响应结构,以此明确指定application/json类型和响应体schema。修改注解如下:

#* @response 403 Forbidden {"description": "Permission denied", "content": {"application/json": {"schema": {"type": "object", "properties": {"error": {"type": "string"}, "message": {"type": "string"}}}}}}
#* @response 404 Not Found {"description": "Model file not found", "content": {"application/json": {"schema": {"type": "object", "properties": {"error": {"type": "string"}, "message": {"type": "string"}}}}}}

这样生成的OpenAPI规范会直接识别403、404响应的application/json类型。

2. 全局配置错误响应序列化器

在API入口文件添加全局错误序列化器,统一覆盖所有错误状态码的响应格式,避免逐个路由重复配置:

pr <- plumber::plumber$new()
# 全局设置错误响应为JSON格式
pr$setErrorSerializer(function(err, req, res) {
  res$setHeader("Content-Type", "application/json")
  jsonlite::toJSON(list(
    error = err$message,
    status = err$status
  ), auto_unbox = TRUE)
})

该配置会让所有错误(包括403、404)自动返回application/json类型的结构化响应。

3. 路由内手动控制错误响应

在业务逻辑触发错误场景时,手动设置响应头、状态码并返回JSON格式内容:

function(res, req, file_id) {
  future::future({
    # 模拟权限校验逻辑
    if (!check_user_permission(req)) {
      res$status <- 403
      res$setHeader("Content-Type", "application/json")
      return(jsonlite::toJSON(
        list(error = "Forbidden", message = "无资源访问权限"), 
        auto_unbox = TRUE
      ))
    }
    
    loaded_model <- find_or_download_model(file_id, env_var$model_local_dir, 
                                          env_var$model_s3_bucket, env_var$model_s3_endpoint, 
                                          env_var$s3_accesskey, env_var$s3_secretkey)
    
    if (is.null(loaded_model)) {
      res$status <- 404
      res$setHeader("Content-Type", "application/json")
      return(jsonlite::toJSON(
        list(error = "Not Found", message = paste("模型文件", file_id, "不存在")), 
        auto_unbox = TRUE
      ))
    }
    
    return("Success, File Found.")
  })
}

这种方式可针对特定业务场景精准控制错误响应内容,同时确保OpenAPI规范能识别响应类型。

4. 路由级错误序列化器注解

如果仅需当前路由的错误响应使用JSON格式,可添加@errorSerializer注解:

#* @get /predict/<file_id>
#* @param file_id:string ID or name of the RDS file
#* @serializer html
#* @errorSerializer json
#* @response 403 Forbidden
#* @response 404 Not Found

该注解会让当前路由的错误响应自动使用JSON序列化器,设置Content-Type为application/json。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 02:23:20