URL中的点导致ASP.NET MVC和IIS返回404错误

321
我有一个项目需要在URL的路径中包含点(.), 例如我可能会有一个URL,如www.example.com/people/michael.phelps。
带点的URL会生成404错误。我的路由没问题。如果我传入没有点的michaelphelps,那么一切正常。如果我加上点(.)就会出现404错误。示例站点正在运行Windows 7和IIS8 Express。URLScan未运行。
我尝试向web.config添加以下内容:
<security>
  <requestFiltering allowDoubleEscaping="true"/>
</security>

很遗憾,这并没有产生任何影响。我只是收到了404.0未找到错误。

这是一个MVC4项目,但我不认为这很重要。我的路由工作正常,并且我期望的参数都在那里,直到它们包含一个点。

我需要配置什么才能在我的URL中使用点号?


101
我花了很多时间才弄清楚这个问题。如果末尾加上斜杠,URL就能正常工作。例如,www.example.com/people/michael.phelps/,但是没有斜杠时,IIS会报404错误。 - Mark
19
这是因为没有斜杠时,IIS会把它认为是一个需要查找的文件。添加斜杠的效果是告诉IIS这不是一个真实的文件。此外,下面的配置选项告诉IIS如果不是文件,则尝试进行路由。 - Tommy
4
对我来说这不起作用。URL内包含点号时,它可以正常工作,但当它在末尾时会出现错误。 - Arcadian
@magic-c0d3r,您是指“.”是URL的最后一个字符还是仅在URL的最后一个单词中出现? - Mark
句点正在调用静态文件处理程序。在web.config中设置runAllManagedModulesForAllRequests="true",它就可以工作了。 - user2320464
显示剩余2条评论
18个回答

390

我编辑了网站的HTTP处理程序,使它能够正常工作。对于我的需求,这个方法很好地解决了我的问题。

我只是添加了一个新的HTTP处理程序来查找特定的路径条件。如果请求符合条件,则正确地将其发送到.NET进行处理。与URLRewrite hack或启用RAMMFAR相比,我更喜欢这种解决方案。

例如,若要让.NET处理URL www.example.com/people/michael.phelps,请在您网站的web.config文件的system.webServer/handlers元素中添加以下行:

<add name="ApiURIs-ISAPI-Integrated-4.0"
     path="/people/*"
     verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS"
     type="System.Web.Handlers.TransferRequestHandler"
     preCondition="integratedMode,runtimeVersionv4.0" />

编辑

还有其他帖子建议解决此问题的方法是启用RAMMFARRunAllManagedModulesForAllRequests选项。启用此选项将在所有请求中启用所有托管模块。这意味着不需要处理静态文件,如图像、PDF和其他文件时,它们也会被.NET处理。除非您有特殊情况,否则最好不要开启此选项。


3
这是一个完整的示例,基于这个答案:https://dev59.com/PGgt5IYBdhLWcg3w5xg_#16607685 - V.B.
12
在添加了[path="*"]后,所有对于像.css、.js这样的静态文件的请求都失败了。我有一个自定义路由来处理这样的URL:"http://domain/ABCDE.FGHIJ"。所有的静态文件都在我的/Content目录中。有没有办法将整个目录排除在外?将RAMMFAR设置为true可以解决问题,但我想避免这种额外开销。 - lamarant
2
本地IIS需要以斜杠开头,但是IIS8只能理解没有第一个斜杠的路由。 - Pavel Voronin
3
我和 @lamarant 遇到了同样的问题... 它会阻止静态文件。你知道为什么吗?我在使用MVC4。 - eestein
3
它适用于MVC5,但如果在路径开头加上斜杠,则只有在路径紧跟主机名后时(而不是相对于应用程序文件夹),它才能正常工作。例如,路径/people/*将适用于www.example.com/people/michael.phelps,但不适用于www.example.com/app/people/michael.phelps。据我所知,无法使路径相对于应用程序。 - Hogan
显示剩余14条评论

51

经过一些尝试,我发现 relaxedUrlToFileSystemMapping 对我来说根本不起作用。而对我有效的是将 RAMMFAR 设置为 true,这个在 (.net 4.0 + mvc3) 和 (.net 4.5 + mvc4) 中同样适用。

<system.webserver>
    <modules runAllManagedModulesForAllRequests="true">

设置RAMMFAR为true时要注意 Hanselman关于RAMMFAR和性能的文章


6
好的,我会尽力进行翻译。以下是需要翻译的内容:Be aware when setting RAMMFAR... Is there any performance loss if i use this <modules runAllManagedModulesForAllRequests="true">请注意,在设置RAMMFAR时要小心...如果我使用这个<modules runAllManagedModulesForAllRequests="true">会有性能损失吗? - Shanker Paudel
1
对于原帖发布者而言,这并不是必需的,因为他正在使用IIS7及以上版本。在那里,它是默认设置,设置RAMMFAR确实会让您付出额外的代价。请参阅http://msdn.microsoft.com/en-us/library/cc668201%28v=vs.100%29.aspx#configuration_settings_for_routing。 - Richard
虽然这很有用,但对于我来说,这还不足以使 MVC5/IIS7 中的周期停止返回 404。 - Chris Moschini
再次重申,你想避免启用这个选项。 - Strake
如果可能的话,请不要在实际网站上执行此操作。 - NickG
它可以工作,但应该在最后加上 / 字符:<modules runAllManagedModulesForAllRequests="true" />。 - telatkaya

30

我在这个问题上卡了很长时间,尝试了各种不同的解决方法都没有成功。

我注意到,当在包含点号[.]的URL末尾添加斜杠[/]时,它不会抛出404错误,而且实际上可以正常工作。

最终,我使用类似于IIS URL Rewrite的URL重写器来监视特定模式并添加训练用斜线来解决了这个问题。

我的URL看起来像这样:/Contact/~firstname.lastname,所以我的模式很简单:/Contact/~(.*[^/])$

我从Scott Forsyth那里得到了这个想法,请参见下面的链接: http://weblogs.asp.net/owscott/handing-mvc-paths-with-dots-in-the-path


这对我有用(MVC5)。上面的其他建议都没有起作用,也不需要,只需要一个尾随斜杠。我将按照@jonduncan05在这里建议的更改我的路由。 - markau
谢谢,Leon。你救了我一天。不确定这里其他人在谈论的所有web.config方面的事情,但是添加尾部斜杠是我所需要的答案。在我的情况下,我对服务器端控制器和调用它的JavaScript有控制,因此我只需更新JavaScript即可! - Frog Pr1nce

29

我相信你需要在web.config中设置relaxedUrlToFileSystemMapping属性。 Haack 最近写了一篇关于此的文章(还有一些其他SO帖子问类似的问题)

<system.web>
<httpRuntime relaxedUrlToFileSystemMapping="true" />

编辑 从下面的评论中可以看出,较新版本的.NET / IIS可能需要将此放在system.WebServer元素中。

<system.webServer>
<httpRuntime relaxedUrlToFileSystemMapping="true" />

3
这是我在mvc3+.net4.0中使用的东西,效果很好,但在mvc4+.net4.5中不再起作用。 - Tadeu Maia
5
我尝试了 relaxedUrlToFileSystemMapping,但没有成功。我认为它不适用于最新版本的MVC。 - Mark
这使我能够捕获URL /WEB-INF./web.xml并在许多其他尝试失败时将其重定向到自定义错误页面。 - quentin-starin
4
有趣。考虑到这种方法对你无效,我本来以为这对我也不起作用...因为我用的是带有.NET4.5的MVC4。但是,哎呀,它还是奏效了。在我的情况下,我只是将一个以句点“.”结尾的URL传入,之前一直报404错误,但使用这种方法后问题就解决了。 - PandaWood
这会有安全影响吗? - Paesano2000
显示剩余5条评论

21

只需将此部分添加到Web.config中,所有对route/{*pathInfo}的请求都将由指定处理程序处理,即使pathInfo中有点也是如此。 (取自ServiceStack MVC Host Web.config示例和此答案https://dev59.com/PGgt5IYBdhLWcg3w5xg_#12151501

这对IIS 6和7都适用。您可以通过修改'add'元素中的path ="*"来为不同路径分配特定的处理程序。

  <location path="route">
    <system.web>
      <httpHandlers>
        <add path="*" type="System.Web.Handlers.TransferRequestHandler" verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" />
      </httpHandlers>
    </system.web>
    <!-- Required for IIS 7.0 -->
    <system.webServer>
      <modules runAllManagedModulesForAllRequests="true" />
      <validation validateIntegratedModeConfiguration="false" />
      <handlers>
        <add name="ApiURIs-ISAPI-Integrated-4.0" path="*" type="System.Web.Handlers.TransferRequestHandler" verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" preCondition="integratedMode,runtimeVersionv4.0" />
      </handlers>
    </system.webServer>
  </location>

4
注意 runAllManagedModulesForAllRequests(RAMMFAR)的性能后果。这将为每个请求启用所有托管模块。IIS可以直接处理静态文件,例如图像,但是RAMMFAR会通过每个模块对它们进行处理,从而增加每个请求的开销。 - Mark
@MarkS。是的,但我认为这只会影响到对路由/...的请求,如果我们使用<location>部分并且不在主<system.webServer>部分中设置runAllManagedModulesForAllRequests。 - V.B.
@V.B. 我认为只需要处理程序就足够了,除非您的系统上有与 .NET 应该处理的 URL 匹配的文件。出于某种原因,RAMMFAR 在 <location> 级别上没有起作用,但处理程序解决方案却可以。 - webXL
当您不希望MVC处理特定路由的请求时,需要使用@webXL <location>,并添加routes.IgnoreRoute("route / {* pathInfo}"); 然后,IIS将查看<location路径=“ route”>中的位置部分,并使用位置部分中指定的处理程序,但它将完全绕过MVC的路由和其他MVC的管道步骤。在我的项目中,如果没有这个设置,ServiceStack api就无法正常工作。 - V.B.
为什么仅仅添加处理程序不起作用?在我的情况下,我必须连同处理程序一起添加RAMMFAR。在这里寻找一些好的解释。 :) - Aditya Patil
显示剩余2条评论

6

MVC 5.0 的解决方法。

许多建议的答案在 MVC 5.0 上似乎不起作用。

由于上一节中的 404 点问题可以通过在该部分后面加上尾随斜杠来解决,因此这里是我使用的小技巧,简洁明了。

在保持视图中方便的占位符的同时:

@Html.ActionLink("Change your Town", "Manage", "GeoData", new { id = User.Identity.Name }, null)

添加一些jQuery/JavaScript即可完成任务:

<script>
    $('a:contains("Change your Town")').on("click", function (event) {
        event.preventDefault();
        window.location.href = '@Url.Action("Manage", "GeoData", new { id = User.Identity.Name })' + "/";
    });</script>

请注意末尾的斜杠,它负责更改。
http://localhost:51003/GeoData/Manage/user@foo.com

转换为

http://localhost:51003/GeoData/Manage/user@foo.com/

5

对于只在一个网页上出现此问题的人来说,解决方案非常简单。编辑您的actionlink,在末尾加上+“/”。

  @Html.ActionLink("Edit", "Edit", new { id = item.name + "/" }) |

解决了我的问题!简单而优雅!最让人烦恼的是,在Windows 10开发期间它可以不用'/',但在Windows 2012上似乎需要。 - Wim ten Brink

3

根据您对保留URI不带查询字符串的重视程度,您还可以将值作为查询字符串的一部分传递,而不是URI。

例如,www.example.com/people?name=michael.phelps 将起作用,无需更改任何设置或其他内容。

这种解决方案虽然失去了具有干净URI的优雅之处,但不需要更改或添加任何设置或处理程序。


2
您可能想考虑使用破折号而不是句号。
Pro ASP MVC 3 Framework 中,它建议在创建友好的URL时应避免使用符号、代码和字符序列。如果您需要一个单词分隔符,请使用破折号(/my-great-article)。下划线不友好,URL编码的空格很奇怪(/my+great+article)或令人讨厌(/my%20great%20article)。
它还提到URL应易于阅读和更改。也许考虑使用破折号而不是点的原因也来自同一本书:
不要为HTML页面使用文件名扩展名(.aspx或.mvc),但对于特定的文件类型(.jpg、.pdf、.zip等)请使用它们。如果适当设置MIME类型,Web浏览器不关心文件名扩展名,但人们仍然希望PDF文件以.pdf结尾。
所以,虽然句号对人类来说仍然可读(尽管在我看来比破折号更难读),但根据句号后面的内容,它仍可能有点令人困惑/误导。如果有人姓Zip,那么URL将是/John.zip而不是/John-zip,即使是编写应用程序的开发人员也会被这种情况所误导。

很可能是用户名或其他本质上包含点的字段。话说,StackOverflow会在其用户URL中将所有标点符号(包括.)替换为破折号:P - jli
我遇到了这个问题,因为我有一个安全的文件检索服务,显然包含路由参数中的文件名... - FlavorScape
因为显然没有回答问题,所以被踩了。如果可以的话,我不会让句号出现在我的 URL 中。它们出现是因为 URL 是生成的,必须是人类可读的。 - mg30rg

1

在Web.config档案中添加URL重写规则。您需要已经在IIS中安装了URL Rewrite模块。使用以下重写规则作为自己的灵感。

<?xml version="1.0" encoding="utf-8"?>
<configuration>

<system.webServer>
  <rewrite>
    <rules>
      <rule name="Add trailing slash for some URLs" stopProcessing="true">
        <match url="^(.*(\.).+[^\/])$" />
          <conditions>
              <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
              <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
          </conditions>
          <action type="Redirect" url="{R:1}/" />
      </rule>
    </rules>
    </rewrite>
</system.webServer>

</configuration> 

这绝对可行,并且由Suprotim Agarwal在2015年在此处介绍:https://www.devcurry.com/2015/07/allowing-dots-in-aspnet-mvc-paths.html - StackOverflowUser

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接