我可以让 KTOR 路由不区分大小写吗?
Can I make KTOR routing case insensitive?
我刚刚用 KTOR 创建了一个服务器 API。这是一些简化的代码:
fun Application.configureRouting() {
routing {
route("/MyPage", HttpMethod.Get) {
handle {
call.respondText(text = "Blah", status = HttpStatusCode.OK )
}
}
}
}
如果我随后请求 /mypage
而不是 /MyPage
,我会收到 404。
现在我明白 技术上,URL 路径 区分大小写,但我不想要 URL 在我的 API 中。
如何设置路由以便“MYPAGE”、“mypage”、“MyPaGe”和所有其他大小写混合排列都将触发同一个处理程序?
我查看了文档并查看了一些代码,但都无济于事。我主要是一名 .NET 开发人员,请放轻松!
谢谢
更新 - 部分解决方案,在多个指定路径上使用相同的处理程序:
fun Application.configureRouting() {
val handler: PipelineInterceptor<Unit, ApplicationCall> = {
call.respondText(text = "Blah", status = HttpStatusCode.OK)
}
routing {
route("/mypage", HttpMethod.Get) {
handle(handler)
}
route("/MyPage", HttpMethod.Get) {
handle(handler)
}
}
}
您可以编写自己的路由选择器 (RouteSelector) 来比较忽略大小写的路径段。最重要的是,您可以编写构建器方法来使用该选择器创建路由。下面是一个 get
构建器方法的示例,它有条件地使用自定义选择器来比较常量(没有参数、通配符等)忽略大小写的路径段:
import io.ktor.http.*
import io.ktor.server.application.*
import io.ktor.server.engine.*
import io.ktor.server.netty.*
import io.ktor.server.response.*
import io.ktor.server.routing.*
import io.ktor.util.pipeline.*
fun main() {
embeddedServer(Netty, port = 2020) {
routing {
get("/some") {
call.respondText { "Case sensitive" }
}
get("/foo", ignoreCase = true) {
call.respondText { "Case insensitive" }
}
}
}.start()
}
fun Route.get(path: String, ignoreCase: Boolean, body: PipelineInterceptor<Unit, ApplicationCall>): Route {
return route(path, HttpMethod.Get, ignoreCase) { handle(body) }
}
fun Route.route(path: String, method: HttpMethod, ignoreCase: Boolean, build: Route.() -> Unit): Route {
val selector = HttpMethodRouteSelector(method)
return routeFromPath(path, ignoreCase).createChild(selector).apply(build)
}
fun Route.routeFromPath(path: String, ignoreCase: Boolean): Route {
val parts = RoutingPath.parse(path).parts
var current: Route = this
for (index in parts.indices) {
val (value, kind) = parts[index]
val selector = when (kind) {
RoutingPathSegmentKind.Parameter -> PathSegmentSelectorBuilder.parseParameter(value)
RoutingPathSegmentKind.Constant -> if (ignoreCase) {
CaseInsensitivePathSelector(value)
} else {
PathSegmentSelectorBuilder.parseConstant(value)
}
}
// there may already be entry with same selector, so join them
current = current.createChild(selector)
}
if (path.endsWith("/")) {
current = current.createChild(TrailingSlashRouteSelector)
}
return current
}
class CaseInsensitivePathSelector(val value: String): RouteSelector() {
override fun evaluate(context: RoutingResolveContext, segmentIndex: Int): RouteSelectorEvaluation = when {
segmentIndex < context.segments.size && context.segments[segmentIndex].equals(value, ignoreCase = true) ->
RouteSelectorEvaluation.ConstantPath
else -> RouteSelectorEvaluation.FailedPath
}
}
我刚刚用 KTOR 创建了一个服务器 API。这是一些简化的代码:
fun Application.configureRouting() {
routing {
route("/MyPage", HttpMethod.Get) {
handle {
call.respondText(text = "Blah", status = HttpStatusCode.OK )
}
}
}
}
如果我随后请求 /mypage
而不是 /MyPage
,我会收到 404。
现在我明白 技术上,URL 路径 区分大小写,但我不想要 URL 在我的 API 中。
如何设置路由以便“MYPAGE”、“mypage”、“MyPaGe”和所有其他大小写混合排列都将触发同一个处理程序?
我查看了文档并查看了一些代码,但都无济于事。我主要是一名 .NET 开发人员,请放轻松!
谢谢
更新 - 部分解决方案,在多个指定路径上使用相同的处理程序:
fun Application.configureRouting() {
val handler: PipelineInterceptor<Unit, ApplicationCall> = {
call.respondText(text = "Blah", status = HttpStatusCode.OK)
}
routing {
route("/mypage", HttpMethod.Get) {
handle(handler)
}
route("/MyPage", HttpMethod.Get) {
handle(handler)
}
}
}
您可以编写自己的路由选择器 (RouteSelector) 来比较忽略大小写的路径段。最重要的是,您可以编写构建器方法来使用该选择器创建路由。下面是一个 get
构建器方法的示例,它有条件地使用自定义选择器来比较常量(没有参数、通配符等)忽略大小写的路径段:
import io.ktor.http.*
import io.ktor.server.application.*
import io.ktor.server.engine.*
import io.ktor.server.netty.*
import io.ktor.server.response.*
import io.ktor.server.routing.*
import io.ktor.util.pipeline.*
fun main() {
embeddedServer(Netty, port = 2020) {
routing {
get("/some") {
call.respondText { "Case sensitive" }
}
get("/foo", ignoreCase = true) {
call.respondText { "Case insensitive" }
}
}
}.start()
}
fun Route.get(path: String, ignoreCase: Boolean, body: PipelineInterceptor<Unit, ApplicationCall>): Route {
return route(path, HttpMethod.Get, ignoreCase) { handle(body) }
}
fun Route.route(path: String, method: HttpMethod, ignoreCase: Boolean, build: Route.() -> Unit): Route {
val selector = HttpMethodRouteSelector(method)
return routeFromPath(path, ignoreCase).createChild(selector).apply(build)
}
fun Route.routeFromPath(path: String, ignoreCase: Boolean): Route {
val parts = RoutingPath.parse(path).parts
var current: Route = this
for (index in parts.indices) {
val (value, kind) = parts[index]
val selector = when (kind) {
RoutingPathSegmentKind.Parameter -> PathSegmentSelectorBuilder.parseParameter(value)
RoutingPathSegmentKind.Constant -> if (ignoreCase) {
CaseInsensitivePathSelector(value)
} else {
PathSegmentSelectorBuilder.parseConstant(value)
}
}
// there may already be entry with same selector, so join them
current = current.createChild(selector)
}
if (path.endsWith("/")) {
current = current.createChild(TrailingSlashRouteSelector)
}
return current
}
class CaseInsensitivePathSelector(val value: String): RouteSelector() {
override fun evaluate(context: RoutingResolveContext, segmentIndex: Int): RouteSelectorEvaluation = when {
segmentIndex < context.segments.size && context.segments[segmentIndex].equals(value, ignoreCase = true) ->
RouteSelectorEvaluation.ConstantPath
else -> RouteSelectorEvaluation.FailedPath
}
}