Точки в URL вызывают 404 с ASP.NET MVC и IIS

303

У меня есть проект, который требует, чтобы у моих 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 Not Found.

Это проект MVC4, но я не думаю, что это актуально. Моя маршрутизация работает нормально, и параметры, которые я ожидаю, есть, пока они не содержат точку.

Что мне нужно настроить, чтобы в моем URL могли быть точки?

отметка
источник
93
Не могу поверить, что я потратил столько времени на это. URL работает нормально, если я добавляю косую черту. Например, www.example.com/people/michael.phelps/, однако без косой черты IIS выдает ошибку 404.
Марк
15
Марк - это потому, что без косой черты IIS считает, что это файл, который он должен найти и найти. Добавление косой черты имеет эффект ... это не настоящий файл. Кроме того, параметр конфигурации, приведенный ниже, сообщает IIS, что если это не файл, попробуйте вместо этого направить его.
Томми
У меня та же проблема после того, как я обновил свой проект до mvc 4 + asp.net 4.5.
Тадеу Майя
В качестве обходного пути я использую IIS Rewrite, чтобы добавить косую черту в мои URL-адреса.
Марк
4
Это не работает для меня. URL отлично работает с "." внутри URL, но когда он находится в самом конце, он выдает ошибку
Arcadian

Ответы:

379

Я получил это, отредактировав обработчики HTTP моего сайта. Для моих нужд это работает хорошо и решает мою проблему.

Я просто добавил новый обработчик HTTP, который ищет конкретные критерии пути. Если запрос совпадает, он правильно отправляется в .NET для обработки. Я гораздо счастливее с этим решением, что взлом URLRewrite или включение 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" />

редактировать

Есть другие сообщения, предполагающие, что решение этой проблемы - RAMMFARили RunAllManagedModulesForAllRequests. Включение этой опции включит все управляемые модули для всех запросов. Это означает, что статические файлы, такие как изображения, PDF-файлы и все остальное, будут обрабатываться .NET, когда в этом нет необходимости. Этот вариант лучше не использовать, если у вас нет для него конкретного случая.

отметка
источник
3
Вот полный пример stackoverflow.com/a/16607685/801189 на основе этого ответа
VB
10
после добавления этого с помощью [path = "*"] все запросы к любым статическим файлам, таким как .css, .js, завершаются неудачей. У меня есть собственный маршрут, который обрабатывает URL, которые выглядят как этот " домен / ABCDE.FGHIJ ". Все мои статические файлы находятся в моей директории / Content. Есть ли способ исключить весь этот каталог из этого? установка RAMMFAR на true работает, но я бы хотел избежать этих накладных расходов.
ламарант
2
Локальный IIS работает с начальным слешем, но IIS8 понимает маршрут только без первого слеша.
Павел Воронин
2
У меня та же проблема, что и у @lamarant ... Он блокирует статические файлы. Ты знаешь почему? Используя MVC4 здесь.
Eestein
3
Он работает в MVC5, но если поставить косую черту в начале пути, он работает только тогда, когда путь идет сразу после имени хоста (он не относится к папке приложения). Например, path / people / * будет работать для www.example.com/people/michael.phelps, но не для www.example.com/app/people/michael.phelps. AFAIK нет способа сделать путь относительно приложения.
Хоган
46

После некоторого осмотра я обнаружил, что relaxedUrlToFileSystemMapping вообще не работал для меня, в моем случае работало то, что для RAMMFAR было установлено значение true, то же самое верно для (.net 4.0 + mvc3) и (.net 4.5 + mvc4).

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

Имейте в виду, что при настройке RAMMFAR верно сообщение Hanselman о RAMMFAR и производительности

Тадеу Майя
источник
5
Имейте в виду , когда установка RAMMFAR ... Есть ли потери производительности , если я использую это <модули runAllManagedModulesForAllRequests = «истинный»>
Шэнкер Paudel
1
В случае с оригинальным постером это не нужно, так как он использует IIS7 и выше. Там это значение по умолчанию и настройка RAMMFAR действительно стоит вам exta. См. Msdn.microsoft.com/en-us/library/…
Ричард
Хотя это полезно, этого было недостаточно, чтобы получить периоды, чтобы перестать возвращать 404s в MVC5 / IIS7 для меня.
Крис Москини
Просто чтобы повторить. Вы хотите не включать эту опцию
Strake
Не делайте этого на живом сайте, если это вообще возможно.
NickG
27

Я считаю, что вы должны установить свойство relaxedUrlToFileSystemMapping в вашем файле web.config. Хаак недавно написал статью об этом (и есть несколько других постов SO, задающих те же вопросы)

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

Редактировать Из комментариев ниже, более поздние версии .NET / IIS могут требовать, чтобы это было в system.WebServerэлементе.

<system.webServer>
<httpRuntime relaxedUrlToFileSystemMapping="true" />
Томми
источник
2
Это то, что я имел с mvc3 + .net4.0 и прекрасно работал, но больше не работает с mvc4 + .net4.5.
Тадеу Майя
4
Я попытался relaxedUrlToFileSystemMapping без успеха. Я не думаю, что это работает с новейшими версиями MVC.
Марка
Это позволило мне перехватить URL /WEB-INF./web.xml и перенаправить его на пользовательскую страницу с ошибкой, когда многие другие способы, которые я пробовал, не работали.
Квентин Старин
3
Интересный. Учитывая, что это не сработало для вас, я собирался предположить, что это не сработает для меня ... учитывая, что я нахожусь на MVC4 с .NET4.5. Но, бинго, все равно сработало. В моем случае у меня просто был URL с точкой "." как последний персонаж. Я получал 404, но это исправило это.
PandaWood
Есть ли у него последствия для безопасности?
Paesano2000
23

Я застрял в этом вопросе в течение долгого времени после бесполезного следования всем различным средствам.

Я заметил, что при добавлении косой черты [/] в конец URL-адреса, содержащего точки [.], Он не выдавал ошибку 404 и фактически работал.

Я наконец решил проблему, используя переписывающее устройство URL, такое как IIS URL Rewrite, чтобы отслеживать конкретный шаблон и добавлять косую черту обучения.

Мой URL выглядит следующим образом: /Contact/~firstname.lastname, поэтому мой шаблон просто: /Contact/~(.*[^/])$

Я получил эту идею от Скотта Форсайта, см. Ссылку ниже: http://weblogs.asp.net/owscott/handing-mvc-paths-with-dots-in-the-path

Леон ван Вик
источник
Это сработало для меня (MVC5). Другие предложения, приведенные выше, не сработали и не были нужны, просто косая черта. Я изменю свои маршруты, как предложено @ jonduncan05 здесь .
Маркау
Спасибо, Леон. Спас день для меня. Не уверен во всех вещах web.config, о которых люди здесь говорили, но добавление заключительного / было ответом, который мне был нужен. В моем случае у меня есть контроль над контроллером на стороне сервера и javascript, который его вызывал, поэтому я просто обновил JavaScript и вуаля!
Frog Pr1nce
21

Просто добавьте этот раздел в Web.config, и все запросы к маршруту / {* pathInfo} будут обрабатываться указанным обработчиком, даже если в pathInfo есть точки. (взято из примера ServiceStack MVC Host Web.config и этого ответа https://stackoverflow.com/a/12151501/801189 )

Это должно работать как для IIS 6, так и для 7. Вы можете назначить определенные обработчики различным путям после «маршрута», изменив path = "*" в элементах "add"

  <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>
VB
источник
2
Остерегайтесь последствий для производительности, которые имеет runAllManagedModulesForAllRequests (RAMMFAR). Это активирует все управляемые модули для каждого запроса. Статические файлы, такие как изображения, могут обрабатываться IIS напрямую, но это обрабатывает их через каждый модуль, добавляя накладные расходы к каждому запросу.
Марк
@Метки. да, но я считаю, что это повлияет только на запрос маршрутизации / ..., если мы используем раздел <location> и не устанавливаем runAllManagedModulesForAllRequests в основном разделе <system.webServer>.
VB
@VB Я думаю, что достаточно обработчика, если у вас нет файлов в системе, которые соответствуют URL, который должен обрабатывать .NET. И по какой-то причине RAMMFAR не работал на уровне <location>, но решение с обработчиком работало.
webXL
@webXL <location> необходим, если вы не хотите, чтобы MVC обрабатывал запросы к указанному маршруту и ​​добавлял маршруты .IgnoreRoute ("route / {* pathInfo}"); Затем IIS изучит раздел местоположения <location path = "route"> и будет использовать указанные обработчики в разделе местоположения, но полностью пропустит маршрутизацию MVC и другие этапы конвейера MVC. В моем проекте ServiceStack API просто не работает без этой настройки.
VB
Почему бы просто не добавить обработчик? В моем случае я должен добавить RAMMFAR вместе с обработчиком. Ищете хорошее объяснение здесь. :)
Адитья Патил
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 это, кажется, требуется.
Вим тен Бринк
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, но люди по-прежнему ожидают, что файлы PDF заканчиваются на .pdf

Таким образом, хотя период все еще читаем для людей (хотя и менее читабелен, чем тире, IMO), он может все еще немного сбивать с толку / вводить в заблуждение в зависимости от того, что происходит после периода. Что делать, если у кого-то есть фамилия zip? Тогда URL будет /John.zip вместо / John-zip, что может ввести в заблуждение даже разработчика, написавшего приложение.

sdm350
источник
Вероятно, это имя пользователя или другое поле, которое по своей сути содержит точки. Тем не менее, StackOverflow заменяет все знаки препинания (включая .) тире в URL-
адресах
Я столкнулся с этим, потому что у меня есть безопасная служба поиска файлов, которая, очевидно, содержит имена файлов в параметре маршрута ...
FlavorScape
Проголосовал по очевидной причине: он не отвечает на вопрос. Если бы я мог, я не позволил бы периодам появляться в моем URL. Они появляются, потому что URL сгенерирован и должен быть удобочитаемым.
mg30rg
2

В зависимости от того, насколько важно сохранить ваш URI без строк запроса, вы также можете просто передать значение с точками как часть строки запроса, а не URI.

Например, www.example.com/people?name=michael.phelps будет работать без изменения каких-либо настроек или чего-либо еще.

Вы теряете элегантность наличия чистого URI, но это решение не требует изменения или добавления каких-либо настроек или обработчиков.

GR7
источник
1

Можно ли изменить структуру URL?
Для чего я работал, я попробовал маршрут для

url: "Download/{fileName}"

но он потерпел неудачу с чем-либо, что имело. в этом.

Я переключил маршрут на

    routes.MapRoute(
        name: "Download",
        url:  "{fileName}/Download",
        defaults: new { controller = "Home", action = "Download", }
    );

Теперь я могу вставить localhost:xxxxx/File1.doc/Downloadи все работает нормально.

Мои помощники в представлении также подобраны на нем

     @Html.ActionLink("click here", "Download", new { fileName = "File1.doc"})

это делает ссылку на localhost:xxxxx/File1.doc/Downloadформат, а также.

Может быть, вы могли бы добавить ненужное слово типа "/ view" или действие в конце вашего маршрута, чтобы ваша собственность могла закончиться /следующим/mike.smith/view

jonduncan05
источник
1

Это так же просто, как изменить путь = " ." к пути = " ". Просто удалите точку в пути для ExensionlessUrlHandler-Integrated-4.0 в web.config.

Вот хорошая статья https://weblog.west-wind.com/posts/2015/Nov/13/Serving-URLs-with-File-Extensions-in-an-ASPNET-MVC-Application

Jonny
источник
Эта ссылка привела меня к лучшему решению моей проблемы (сегмент содержит символ «.», Но клиенты не будут следовать с «/»). Исправлено, когда эта строка была в <system.webServer> web.config - <modules runAllManagedModulesForAllRequests = "true" />
NickBeaugié
1

Перепробовал все решения выше, но ни одно из них не помогло мне. Что сработало, так это то, что я удалил .NET версии> 4.5, включая все многоязычные версии; Со временем я добавил новые (только на английском) версии по частям. Прямо сейчас версии, установленные в моей системе, таковы:

  • 2,0
  • 3.0
  • 3,5 4
  • 4.5
  • 4.5.1
  • 4.5.2
  • 4,6
  • 4.6.1

И это все еще работает на данный момент. Я боюсь установить 4.6.2, потому что это может все испортить.

Так что я мог только предполагать, что либо 4.6.2, либо все эти неанглийские версии испортили мою конфигурацию.

jokab
источник
0

Мне удалось решить мою конкретную версию этой проблемы (пришлось создать /customer.html маршрут к / customer, конечные косые черты не разрешены), используя решение по адресу https://stackoverflow.com/a/13082446/1454265 , и подставив путь = "*. HTML".

user1454265
источник
0

Решением может быть также рассмотрение кодирования в формате, который не содержит символ ., как base64.

В JS должны быть добавлены

btoa(parameter); 

В контроллере

byte[] bytes = Convert.FromBase64String(parameter);
string parameter= Encoding.UTF8.GetString(bytes);
Макс Буревый
источник
0

Добавьте правило перезаписи URL в архив Web.config. У вас должен быть модуль перезаписи URL, уже установленный в IIS. Используйте следующее правило переписывания в качестве вдохновения для своего собственного.

<?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> 
Амадей Санчес
источник
0

Также (связано) проверьте порядок сопоставлений вашего обработчика. У нас был .ashx с .svc (например, /foo.asmx/bar.svc/path) в пути после него. Сначала сопоставление .svc было таким 404 для пути .svc, который соответствовал перед .asmx. Я не слишком много думал, но, возможно, URL позаботится об этом.

stuartm9999
источник
-3
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace WebApplication1.Controllers
{
    [RoutePrefix("File")]
    [Route("{action=index}")]
    public class FileController : Controller
    {
        // GET: File
        public ActionResult Index()
        {
            return View();
        }

        [AllowAnonymous]
        [Route("Image/{extension?}/{filename}")]
        public ActionResult Image(string extension, string filename)
        {
            var dir = Server.MapPath("/app_data/images");

            var path = Path.Combine(dir, filename+"."+ (extension!=null?    extension:"jpg"));
           // var extension = filename.Substring(0,filename.LastIndexOf("."));

            return base.File(path, "image/jpeg");
        }
    }
}
хамьяри афаринеш
источник
1
Как это отвечает на вопрос ОП? Не могли бы вы описать это?
kayess
это не решение, это взлом, который требует, чтобы расширение файла было помещено в путь URI (без точки), например, "~ / Image / jpg / cow" для получения файла "/ app_data / images / cow / jpg" - - не решение, которое этот парень и все остальные находят в этом нуждающемся.
Шон Уилсон