Ktor中/articles端点PUT请求返回404而非405的问题咨询
Ktor Resources插件导致/articles路径PUT请求返回404而非405的解决办法
这是Ktor Resources插件的设计特性:只有当某个资源类存在至少一个对应的路由处理时,Ktor才会将该路径识别为“存在”。根路径因为注册了get<Root>,服务器能识别路径存在,只是PUT方法不被允许,所以返回405;而Articles资源虽然定义了类,但仅配置了GET方法的路由,当请求PUT时,Resources插件未匹配到该资源的任何路由,直接返回404。
以下是几种可行的解决办法:
办法一:为Articles资源显式处理不支持的HTTP方法
直接为Articles资源添加其他HTTP方法的路由,统一返回405并设置Allow头,明确告知允许的方法:
@Resource("/") internal object Root @Resource("articles") internal data class Articles(val parent: Root = Root) fun main() { embeddedServer(CIO, port = 8080){ install(Resources) routing { get<Root> { call.respondText("articles/") } get<Articles> { call.respondText("articles list") } // 处理PUT请求返回405 put<Articles> { call.response.headers.append("Allow", "GET") call.respond(HttpStatusCode.MethodNotAllowed) } // 按需添加POST、DELETE等其他不支持的方法 post<Articles> { call.response.headers.append("Allow", "GET") call.respond(HttpStatusCode.MethodNotAllowed) } } }.start(true) }
办法二:用拦截器统一处理资源路径的方法校验
如果有多个资源需要处理,可自定义拦截器,在路由匹配后检查请求方法是否被允许:
@Resource("/") internal object Root @Resource("articles") internal data class Articles(val parent: Root = Root) fun main() { embeddedServer(CIO, port = 8080){ install(Resources) routing { // 定义各资源允许的HTTP方法 val resourceAllowedMethods = mapOf( Root::class to setOf(HttpMethod.Get), Articles::class to setOf(HttpMethod.Get) ) intercept(ApplicationCallPipeline.Call) { val resourceClass = call.attributes.getOrNull(Resources.Attributes.ResourceClass) resourceClass?.let { clazz -> val allowedMethods = resourceAllowedMethods[clazz] ?: emptySet() if (!allowedMethods.contains(call.request.httpMethod)) { call.response.headers.append("Allow", allowedMethods.joinToString(", ") { it.value }) call.respond(HttpStatusCode.MethodNotAllowed) finish() } } } get<Root> { call.respondText("articles/") } get<Articles> { call.respondText("articles list") } } }.start(true) }
办法三:改用普通路由替代Resources插件
如果不需要Resources的嵌套资源特性,直接使用普通路由定义,Ktor会自动识别路径存在,对不允许的方法返回405:
fun main() { embeddedServer(CIO, port = 8080){ routing { get("/") { call.respondText("articles/") } route("/articles") { get { call.respondText("articles list") } // 匹配所有未定义的方法,返回405 handle { call.response.headers.append("Allow", "GET") call.respond(HttpStatusCode.MethodNotAllowed) } } } }.start(true) }
内容的提问来源于stack exchange,提问作者Vencat
相关产品推荐
相关产品推荐

