如何在Web API 2路径段URL中传递.或..这类点符号?
.或..作为id变量传入的问题 这个问题我之前帮不少开发者排查过,确实是URL规范化在背后起作用!你说的没错,RFC 3986这类URL规范文档里明确规定:仅包含单个.(代表当前目录)或两个.(代表父目录)的路径段,会被自动做简化处理。而且不仅是协议层面,你的Web API宿主(比如IIS)和ASP.NET路由系统默认都会执行这个规范化操作——哪怕你把.编码成%2E发送,服务器也会先解码成.,再执行路径简化,导致你根本拿不到原始的./..值。
那有没有办法实现需求?当然有,给你几个可行的方案:
方案一:禁用URL规范化(需谨慎操作)
可以通过修改web.config让IIS和ASP.NET跳过路径规范化:- 在
<system.web>节点下添加配置,允许非标准URL映射:<httpRuntime relaxedUrlToFileSystemMapping="true" /> - 在
<system.webServer>节点下开启双重转义支持,禁用路径过滤:<security> <requestFiltering allowDoubleEscaping="true" /> </security> - 在Web API路由配置中,确保路由会处理所有请求,不会跳过文件路径匹配:
RouteTable.Routes.RouteExistingFiles = true;
注意:这个方案会带来一定安全风险,比如可能引发目录遍历漏洞,如果API对外暴露,一定要做好额外的权限校验和参数合法性检查。
- 在
方案二:改用查询字符串传参(最安全省心)
把id从路径参数改成查询参数是最简单的规避方式,比如:
原本的请求路径/api/items/..,改成/api/items?id=..
查询字符串里的./..不会被路径规范化逻辑处理,你可以直接通过Action参数绑定或者Request.QueryString["id"]拿到原始值。方案三:自定义路由处理逻辑(适合必须用路径参数的场景)
如果你一定要用路径参数传递,可以写一个自定义RouteHandler,在ASP.NET执行路径规范化之前捕获原始URL,手动解析出id参数:public class CustomRouteHandler : HttpControllerRouteHandler { protected override IHttpHandler GetHttpHandler(RequestContext requestContext) { // 从原始请求URL中提取目标id段 var rawUrl = requestContext.HttpContext.Request.RawUrl; var segments = rawUrl.Split('/'); if (segments.Length > 0) { requestContext.RouteData.Values["id"] = segments.Last(); } return base.GetHttpHandler(requestContext); } }然后在路由配置里指定使用这个自定义处理器:
config.Routes.MapHttpRoute( name: "CustomApiRoute", routeTemplate: "api/items/{id}", defaults: new { controller = "Items", id = RouteParameter.Optional }, routeHandler: new CustomRouteHandler() );
总结一下:RFC的规范是默认行为,但并非完全“禁止”你实现需求,只是需要绕开默认的规范化逻辑。优先推荐查询字符串的方案,安全又不需要复杂配置。
内容的提问来源于stack exchange,提问作者Maxime Rossini

