Kropki w adresie URL powodują 404 z mvc ASP.NET i IIS


303

Mam projekt, który wymaga od moich adresów URL kropek na ścieżce. Na przykład mogę mieć adres URL, taki jak www.example.com/people/michael.phelps

Adresy URL z kropką generują 404. Mój routing jest w porządku. Jeśli przejdę przez Michaelphelpsa, bez kropki, wszystko będzie działać. Po dodaniu kropki pojawia się błąd 404. Przykładowa witryna działa w systemie Windows 7 z IIS8 Express. URLScan nie działa.

Próbowałem dodać do mojego pliku web.config:

<security>
  <requestFiltering allowDoubleEscaping="true"/>
</security>

Niestety nie miało to znaczenia. Właśnie otrzymałem błąd 404.0 Nie znaleziono.

To jest projekt MVC4, ale nie sądzę, żeby to miało znaczenie. Moje routing działa dobrze i oczekiwane parametry są dostępne, dopóki nie zawierają kropki.

Co muszę skonfigurować, aby mieć kropki w moim adresie URL?


93
Nie mogę uwierzyć, że spędziłem na tym tyle czasu. Adres URL działa dobrze, jeśli dodam ukośnik końcowy. Na przykład www.example.com/people/michael.phelps/ jednak bez końcowego ukośnika IIS generuje błąd 404.
Mark

15
Mark - to dlatego, że bez końcowego ukośnika IIS uważa, że ​​jest to plik, który powinien znaleźć i znaleźć. Dodanie ukośnika powoduje ... To nie jest prawdziwy plik. Ponadto poniższa opcja konfiguracji informuje IIS, że jeśli nie jest to plik, spróbuj zamiast tego skierować go.
Tommy

Mam ten sam problem po aktualizacji mojego projektu do mvc 4 + asp.net 4.5.
Tadeu Maia

Aby obejść ten problem, używam IIS Rewrite, aby dodać końcowy ukośnik do moich adresów URL.
Mark

4
To mi nie działa. Adres URL działa poprawnie z „.” w adresie URL, ale gdy jest na samym końcu, wyświetla błąd
Arcadian

Odpowiedzi:


379

Udało mi się to, edytując programy obsługi HTTP mojej witryny. Na moje potrzeby działa to dobrze i rozwiązuje mój problem.

Po prostu dodałem nowy moduł obsługi HTTP, który szuka określonych kryteriów ścieżki. Jeśli żądanie jest zgodne, jest poprawnie wysyłane do platformy .NET w celu przetworzenia. Jestem znacznie bardziej zadowolony z tego rozwiązania, że ​​URLRewrite włamuje się lub włącza RAMMFAR.

Na przykład, aby .NET przetworzył adres URL www.example.com/people/michael.phelps, dodaj następujący wiersz do web.config swojej witryny w system.webServer / handlerselemencie:

<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" />

Edytować

Istnieją inne posty sugerujące, że rozwiązaniem tego problemu jest RAMMFARlub RunAllManagedModulesForAllRequests. Włączenie tej opcji spowoduje włączenie wszystkich zarządzanych modułów dla wszystkich żądań. Oznacza to, że pliki statyczne, takie jak obrazy, pliki PDF i wszystko inne będą przetwarzane przez .NET, gdy nie będą potrzebne. Opcję tę najlepiej pozostawić, chyba że masz do tego konkretny przypadek.


3
oto kompletny przykład stackoverflow.com/a/16607685/801189 na podstawie tej odpowiedzi
VB

10
po dodaniu tego za pomocą [path = "*"] wszystkie żądania do dowolnych plików statycznych, takich jak .css, .js kończą się niepowodzeniem. Mam niestandardową trasę, która obsługuje adresy URL wyglądające jak ta „ domena / ABCDE.FGHIJ ”. Wszystkie moje pliki statyczne znajdują się w moim katalogu / Content. Czy istnieje sposób na wykluczenie z tego całego katalogu? ustawienie RAMMFAR na prawdziwe działa, ale chciałbym uniknąć tego narzutu.
lamarant

2
Lokalne IIS działa z początkowym ukośnikiem, ale IIS8 rozumie trasę tylko bez pierwszego ukośnika.
Pavel Voronin

2
Mam ten sam problem co @lamarant ... Blokuje pliki statyczne. Wiesz dlaczego? Za pomocą MVC4 tutaj.
eestein

3
Działa w MVC5, ale jeśli umieścisz ukośnik na początku ścieżki, działa tylko wtedy, gdy ścieżka znajduje się bezpośrednio po nazwie hosta (nie jest względna do folderu aplikacji). Na przykład ścieżka / ludzie / * działałaby dla www.example.com/people/michael.phelps, ale nie dla www.example.com/app/people/michael.phelps. AFAIK nie ma możliwości, aby ścieżka była względna do aplikacji.
Hogan

46

Po krótkiej analizie okazało się, że zrelaksowaneUrlToFileSystemMapping w ogóle mi nie działało, w moim przypadku działało ustawienie RAMMFAR na true, to samo dotyczy (.net 4.0 + mvc3) i (.net 4.5 + mvc4).

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

Pamiętaj, ustawiając RAMMFAR prawdziwy wpis Hanselmana o RAMMFAR i wydajności


5
Należy pamiętać przy ustawianiu RAMMFAR ... Czy jest jakaś utrata wydajności, jeśli użyję tego <moduły runAllManagedModulesForAllRequests = "true">
Shanker

1
W przypadku oryginalnego plakatu nie powinno to być potrzebne, ponieważ używa IIS7 i nowszych wersji. Jest to ustawienie domyślne, a ustawienie RAMMFAR naprawdę kosztuje exta. Zobacz msdn.microsoft.com/en-us/library/…
Richard

Chociaż jest to przydatne, nie wystarczyło to, aby okresy przestały zwracać 404 w MVC5 / IIS7.
Chris Moschini,

Powtarzam: chcesz uniknąć włączenia tej opcji
Strake

Nie rób tego jednak na działającej stronie, jeśli to w ogóle możliwe.
NickG

27

Uważam, że musisz ustawić właściwość zrelaksowanyUrlToFileSystemMapping w pliku web.config. Haack napisał o tym artykuł jakiś czas temu (i są też inne posty SO zadające takie same pytania)

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

Edycja Z poniższych komentarzy, późniejsze wersje .NET / IIS mogą wymagać tego w system.WebServerelemencie.

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

2
To właśnie miałem z mvc3 + .net4.0 i działałem pięknie, ale nie działam już z mvc4 + .net4.5.
Tadeu Maia

4
Próbowałem zrelaksowanegoUrlToFileSystemMapping bez powodzenia. Nie sądzę, że działa z najnowszymi wersjami MVC.
Mark

Pozwoliło mi to złapać adres URL / WEB-INF./web.xml i przekierować go na niestandardową stronę błędu, gdy wiele innych sposobów, które próbowałem, nie zadziałało.
quentin-starin

3
Ciekawy. Biorąc pod uwagę, że to nie działało dla ciebie, miałem założyć, że to nie zadziała dla mnie ... biorąc pod uwagę, że korzystam z MVC4 z .NET4.5. Ale bingo, i tak zadziałało. W moim przypadku po prostu miałem adres URL z kropką „.” jako ostatni znak. Dostawałem 404, ale to naprawiło.
PandaWood,

Czy ma to wpływ na bezpieczeństwo?
Paesano2000,

23

Utknąłem w tej sprawie przez długi czas, korzystając z różnych środków bezskutecznie.

Zauważyłem, że dodanie ukośnika [/] na końcu adresu URL zawierającego kropki [.] Nie spowodowało błędu 404 i faktycznie działało.

W końcu rozwiązałem ten problem za pomocą przepisywania adresów URL, takiego jak IIS URL Rewrite, w celu wyszukania określonego wzorca i dodania slashu szkoleniowego.

Mój adres URL wygląda następująco: /Contact/~firstname.lastname, więc mój wzór to po prostu: /Contact/~(.*[^/])$

Ten pomysł dostałem od Scott Forsyth, patrz link poniżej: http://weblogs.asp.net/owscott/handing-mvc-paths-with-dots-in-the-path


To zadziałało dla mnie (MVC5). Inne powyższe sugestie nie działały i nie były potrzebne, tylko ukośnik końcowy. Zmienię moje trasy zgodnie z sugestią @ jonduncan05 tutaj .
markau

Dziękuję Leon. Uratowałem mi dzień. Nie jestem pewien co do wszystkich elementów web.config, o których mówią ludzie, ale dodanie końcowego / było odpowiedzią, której potrzebowałem. W moim przypadku mam kontrolę nad kontrolerem po stronie serwera i wywołującym go javascript, więc właśnie zaktualizowałem JavaScript i voila!
Frog Pr1nce

21

Wystarczy dodać tę sekcję do Web.config, a wszystkie żądania do trasy / {* pathInfo} będą obsługiwane przez określony moduł obsługi, nawet jeśli w pathInfo występują kropki. (wzięty z przykładu Web.config hosta ServiceStack MVC i tej odpowiedzi https://stackoverflow.com/a/12151501/801189 )

Powinno to działać zarówno w IIS 6, jak i 7. Można przypisać określone procedury obsługi do różnych ścieżek po „route”, modyfikując path = „*” w elementach „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>

2
Uważaj na konsekwencje wydajnościowe, jakie ma runAllManagedModulesForAllRequests (RAMMFAR). Umożliwi to zarządzanie wszystkimi modułami dla każdego żądania. Pliki statyczne, takie jak obrazy, mogą być przetwarzane bezpośrednio przez IIS, ale to przetwarza je przez każdy moduł, dodając narzut do każdego żądania.
Mark

@Znaki. tak, ale wierzę, że wpłynie to tylko na żądanie trasy / ... jeśli użyjemy sekcji <lokalizacja> i nie ustawimy runAllManagedModulesForAllRequests w głównej sekcji <system.webServer>.
VB

@VB Myślę, że wystarczy moduł obsługi, chyba że masz w systemie pliki, które pasują do adresu URL, który ma przetworzyć .NET. I z jakiegoś powodu RAMMFAR nie działał na poziomie <lokalizacja>, ale rozwiązanie modułu obsługi działało.
webXL

@webXL <lokalizacja> potrzebna, jeśli nie chcesz, aby MVC przetwarzało żądania do określonej trasy i dodawało trasy.IgnoreRoute („route / {* pathInfo}”); Następnie IIS przeszuka sekcję lokalizacji <ścieżka ścieżki = "trasa"> i użyje określonych procedur obsługi w sekcji lokalizacji, ale całkowicie obejdzie routing MVC i inne etapy potoku MVC. W moim projekcie ServiceStack API po prostu nie działa bez tej konfiguracji.
VB

Dlaczego po prostu dodanie modułu obsługi nie zadziała? W moim przypadku muszę dodać RAMMFAR wraz z programem obsługi. Szukasz dobrego wyjaśnienia tutaj. :)
Aditya Patil

6

Obejście MVC 5.0.

Wiele sugerowanych odpowiedzi wydaje się nie działać w MVC 5.0.

Ponieważ problem 404 kropek w ostatniej sekcji można rozwiązać, zamykając tę ​​sekcję ukośnikiem końcowym, oto mała sztuczka, której używam, czysta i prosta.

Zachowując wygodny symbol zastępczy w widoku:

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

dodaj trochę jquery / javascript, aby wykonać zadanie:

<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>

zwróć uwagę na ukośnik końcowy, który jest odpowiedzialny za zmianę

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

w

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

5

Bardzo łatwa odpowiedź dla tych, którzy mają to tylko na jednej stronie internetowej. Edytuj link akcji i znak „/” na jego końcu.

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

Rozwiązałem to dla mnie! Prosty i elegancki! Najbardziej irytujące jest to, że podczas programowania działa bez „/” w systemie Windows 10, ale w przypadku systemu Windows 2012 wydaje się być wymagane.
Wim ten Brink

2

Możesz pomyśleć o użyciu myślników zamiast kropek.

W Pro ASP MVC 3 Framework sugerują to, aby tworzyć przyjazne adresy URL:

Unikaj symboli, kodów i sekwencji znaków. Jeśli potrzebujesz separatora słów, użyj myślnika (/ my-great-article). Podkreślenia są nieprzyjazne, a spacje zakodowane w adresach URL są dziwne (/ my + great + article) lub obrzydliwe (/ my% 20great% 20article).

Wspomina również, że adresy URL powinny być łatwe do odczytania i zmiany dla ludzi. Być może powód, dla którego warto pomyśleć o użyciu myślnika zamiast kropki, również pochodzi z tej samej książki:

Nie używaj rozszerzeń nazw plików dla stron HTML (.aspx lub .mvc), ale używaj ich do specjalnych typów plików (.jpg, .pdf, .zip itp.). Przeglądarki internetowe nie dbają o rozszerzenia nazw plików, jeśli odpowiednio ustawisz typ MIME, ale ludzie nadal oczekują, że pliki PDF kończą się na .pdf

Tak więc, chociaż okres jest nadal czytelny dla ludzi (choć mniej czytelny niż myślniki, IMO), może być nieco mylący / wprowadzający w błąd w zależności od tego, co nastąpi po tym okresie. Co jeśli ktoś ma nazwisko zip? Wtedy URL będzie miał postać /John.zip zamiast / John-zip, co może wprowadzać w błąd nawet dla programisty, który napisał aplikację.


Prawdopodobnie jest to nazwa użytkownika lub inne pole, które z natury zawiera kropki. To powiedziawszy, StackOverflow zastępuje wszelkie znaki interpunkcyjne (w tym .) myślnikami w adresach URL użytkowników: P
jli

Napotkałem to, ponieważ mam bezpieczną usługę pobierania plików, która oczywiście zawiera nazwy plików w parametrze route ...
FlavorScape

Głosowany z oczywistego powodu: nie odpowiada na pytanie. Gdybym mógł, nie pozwoliłbym, aby kropki pojawiały się w moim adresie URL. Pojawiają się, ponieważ adres URL jest generowany i musi być czytelny dla człowieka.
mg30rg

2

W zależności od tego, jak ważne jest zachowanie identyfikatora URI bez kwerend, możesz również przekazać wartość za pomocą kropek jako części kwerendy, a nie identyfikatora URI.

Np. Www.example.com/people?name=michael.phelps będzie działał bez konieczności zmiany jakichkolwiek ustawień lub czegokolwiek.

Tracisz elegancję posiadania czystego identyfikatora URI, ale to rozwiązanie nie wymaga zmiany ani dodawania żadnych ustawień ani procedur obsługi.


1

Czy można zmienić strukturę adresu URL?
Do tego, nad czym pracowałem, próbowałem trasy

url: "Download/{fileName}"

ale zawiodło z czymkolwiek, co miało. w tym.

Zmieniłem trasę na

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

Teraz mogę włożyć localhost:xxxxx/File1.doc/Downloadi działa dobrze.

Moi pomocnicy w widoku również to zauważyli

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

tworzy również link do localhost:xxxxx/File1.doc/Downloadformatu.

Być może możesz umieścić niepotrzebne słowo, takie jak „/ view” lub akcję na końcu trasy, aby Twoja nieruchomość mogła zakończyć się ciągnięciem /czegoś w rodzaju/mike.smith/view


1

To tak proste, jak zmiana ścieżki = " ." do ścieżki = " ". Wystarczy usunąć kropkę na ścieżce dla ExensionlessUrlHandler-Integrated-4.0 w pliku web.config.

Oto fajny artykuł https://weblog.west-wind.com/posts/2015/Nov/13/Serving-URLs-with-File-Extensions-in-an-ASPNET-MVC-Application


Ten link doprowadził mnie do najlepszego rozwiązania mojego problemu (segment zawiera znak „.”, Ale klienci nie będą śledzić za pomocą „/”). Naprawiono poprzez posiadanie tej linii w <system.webServer> web.config - <moduły runAllManagedModulesForAllRequests = "true" />
NickBeaugié

1

Wypróbowałem wszystkie powyższe rozwiązania, ale żadne z nich nie działało dla mnie. Co zadziałało, odinstalowałem wersje .NET> 4.5, w tym wszystkie wersje wielojęzyczne; W końcu dodałem nowsze wersje (tylko w języku angielskim) kawałek po kawałku. Obecnie wersje zainstalowane w moim systemie są następujące:

  • 2.0
  • 3.0
  • 3,5 4
  • 4.5
  • 4.5.1
  • 4.5.2
  • 4.6
  • 4.6.1

I nadal działa w tym momencie. Boję się zainstalować 4.6.2, ponieważ może to wszystko popsuć.

Mogłem więc jedynie spekulować, że albo 4.6.2, albo wszystkie te wersje nieangielskie popsuły moją konfigurację.



0

Jako rozwiązanie można również rozważyć kodowanie do formatu, który nie zawiera symbolu ., jak base64.

W js należy dodać

btoa(parameter); 

W kontrolerze

byte[] bytes = Convert.FromBase64String(parameter);
string parameter= Encoding.UTF8.GetString(bytes);

0

Dodaj regułę przepisywania adresów URL do archiwum Web.config. Musisz mieć moduł URL Rewrite już zainstalowany w IIS. Użyj poniższej reguły przepisywania jako inspiracji dla własnej.

<?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

Ponadto (powiązane) sprawdź kolejność mapowań programu obsługi. Mieliśmy .ashx z .svc (np. /Foo.asmx/bar.svc/path) na ścieżce po nim. Mapowanie .svc było po raz pierwszy tak 404 dla ścieżki .svc, która pasowała przed .asmx. Hav nie myślał za dużo, ale może adres URL ścieżki zakodowałby to.


-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
Jak ta odpowiedź odpowiada na pytanie OP? Czy mógłbyś to opisać?
kayess

to nie jest rozwiązanie, to hack, który wymaga rozszerzenia pliku do ścieżki uri (bez kropki) np. „~ / Image / jpg / cow”, aby pobrać plik „/ app_data / images / cow / jpg” - - nie rozwiązanie tego faceta i wszystkich innych, którzy tego potrzebują.
Shaun Wilson
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.