Les points dans l'URL provoquent 404 avec ASP.NET mvc et IIS

303

J'ai un projet qui nécessite que mes URL aient des points sur le chemin. Par exemple, je peux avoir une URL telle que www.example.com/people/michael.phelps

Les URL avec le point génèrent un 404. Mon routage est très bien. Si je passe à michaelphelps, sans le point, alors tout fonctionne. Si j'ajoute le point, j'obtiens une erreur 404. L'exemple de site s'exécute sur Windows 7 avec IIS8 Express. URLScan n'est pas en cours d'exécution.

J'ai essayé d'ajouter ce qui suit à mon web.config:

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

Malheureusement, cela n'a fait aucune différence. Je viens de recevoir une erreur 404.0 Not Found.

Il s'agit d'un projet MVC4 mais je ne pense pas que ce soit pertinent. Mon routage fonctionne bien et les paramètres que j'attends sont là, jusqu'à ce qu'ils incluent un point.

Que dois-je configurer pour pouvoir avoir des points dans mon URL?

marque
la source
93
Je ne peux pas croire que j'ai passé autant de temps sur celui-ci. L'URL fonctionne correctement si j'ajoute une barre oblique de fin. Par exemple, www.example.com/people/michael.phelps/ mais sans la barre oblique finale, IIS génère une erreur 404.
Mark
15
Mark - c'est parce que sans la barre oblique de fin, IIS pense que c'est un fichier qu'il devrait aller chercher. L'ajout de la barre oblique a pour effet de ... ce n'est pas un vrai fichier. En outre, l'option de configuration ci-dessous indique à IIS que s'il ne s'agit pas d'un fichier, essayez de le router à la place.
Tommy
J'ai le même problème après avoir mis à jour mon projet vers mvc 4 + asp.net 4.5.
Tadeu Maia
En guise de solution, j'utilise IIS Rewrite pour ajouter la barre oblique de fin à mes URL.
Mark
4
Ça ne marche pas pour moi. L'URL fonctionne bien avec "." dans l'URL, mais quand il est à la fin, il donne une erreur
Arcadian

Réponses:

379

J'ai réussi à le faire en modifiant les gestionnaires HTTP de mon site. Pour mes besoins, cela fonctionne bien et résout mon problème.

J'ai simplement ajouté un nouveau gestionnaire HTTP qui recherche des critères de chemin d'accès spécifiques. Si la demande correspond, elle est correctement envoyée à .NET pour traitement. Je suis beaucoup plus heureux avec cette solution que l'URLRewrite pirate ou active RAMMFAR.

Par exemple, pour que .NET traite l'URL www.example.com/people/michael.phelps, ajoutez la ligne suivante au web.config de votre site dans l' system.webServer / handlersélément:

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

Éditer

Il existe d'autres articles suggérant que la solution à ce problème est RAMMFARou RunAllManagedModulesForAllRequests. L'activation de cette option activera tous les modules gérés pour toutes les demandes. Cela signifie que les fichiers statiques tels que les images, les fichiers PDF et tout le reste seront traités par .NET lorsqu'ils ne doivent pas l'être. Il vaut mieux laisser cette option à moins que vous ayez un cas spécifique pour cela.

marque
la source
3
voici un exemple complet stackoverflow.com/a/16607685/801189 basé sur cette réponse
VB
10
après avoir ajouté ceci avec [path = "*"] toutes les demandes à tous les fichiers statiques tels que .css, .js échouent. J'ai un itinéraire personnalisé qui gère les URL qui ressemblent à ce " domaine / ABCDE.FGHIJ ". Tous mes fichiers statiques se trouvent dans mon répertoire / Content. Existe-t-il un moyen d'exclure tout ce répertoire de cela? mettre RAMMFAR sur de vraies œuvres, mais je voudrais éviter cette surcharge.
lamarant
2
IIS local fonctionne avec le démarrage de la barre oblique, mais IIS8 ne comprend l'itinéraire que sans première barre oblique.
Pavel Voronin
2
J'ai le même problème que @lamarant ... Il bloque les fichiers statiques. Est-ce que tu sais pourquoi? Utilisation de MVC4 ici.
eestein
3
Cela fonctionne dans MVC5, mais si vous mettez une barre oblique au début du chemin, cela ne fonctionne que lorsque le chemin se trouve immédiatement après le nom d'hôte (ce n'est pas relatif au dossier de l'application). Par exemple, le chemin / people / * fonctionnerait pour www.example.com/people/michael.phelps, mais pas pour www.example.com/app/people/michael.phelps. AFAIK il n'y a aucun moyen de faire le chemin par rapport à l'application.
Hogan
46

Après quelques fouilles, j'ai trouvé que relaxUrlToFileSystemMapping ne fonctionnait pas du tout pour moi, ce qui fonctionnait dans mon cas était de définir RAMMFAR sur true, la même chose est valable pour (.net 4.0 + mvc3) et (.net 4.5 + mvc4).

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

Soyez conscient lorsque vous définissez RAMMFAR true Hanselman post sur RAMMFAR et ses performances

Tadeu Maia
la source
5
Soyez conscient lors de la configuration de RAMMFAR ... Y a-t-il une perte de performances si j'utilise ce <modules runAllManagedModulesForAllRequests = "true">
Shanker Paudel
1
Dans le cas de l'affiche originale, cela ne devrait pas être nécessaire, car il utilise IIS7 et supérieur. Là, c'est la valeur par défaut et le réglage du RAMMFAR vous coûte en effet exta. Voir msdn.microsoft.com/en-us/library/…
Richard
Bien que cela soit utile, cela n'a pas suffi pour que mes règles cessent de renvoyer 404 dans MVC5 / IIS7.
Chris Moschini
Juste pour réitérer. Vous voulez éviter d'avoir cette option activée
Strake
Ne faites pas cela sur un site en direct si possible.
NickG
27

Je crois que vous devez définir la propriété relaxUrlToFileSystemMapping dans votre web.config. Haack a écrit un article à ce sujet il y a peu de temps (et il y a d'autres articles SO posant le même type de question)

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

Modifier D'après les commentaires ci-dessous, les versions ultérieures de .NET / IIS peuvent nécessiter que cela soit dans l' system.WebServerélément.

<system.webServer>
<httpRuntime relaxedUrlToFileSystemMapping="true" />
Tommy
la source
2
C'est ce que j'avais avec mvc3 + .net4.0 et qui fonctionnait à merveille, mais ne fonctionne plus avec mvc4 + .net4.5.
Tadeu Maia
4
J'ai essayé le RelaxUrlToFileSystemMapping sans succès. Je ne pense pas que cela fonctionne avec les dernières versions de MVC.
Mark
Cela m'a permis d'attraper l'URL /WEB-INF./web.xml et de le rediriger vers une page d'erreur personnalisée lorsque de nombreuses autres façons que j'ai essayées n'ont pas fonctionné.
quentin-star du
3
Intéressant. Étant donné que cela ne fonctionnait pas pour vous, j'étais sur le point de supposer que cela ne fonctionnerait pas pour moi ... étant donné que je suis sur MVC4 avec .NET4.5. Mais le bingo, ça a quand même fonctionné. Dans mon cas, j'avais simplement une URL avec un point "." comme dernier caractère. J'obtenais des 404 mais cela l'a réparé.
PandaWood
Est-ce que cela a des répercussions sur la sécurité?
Paesano2000
23

Je suis resté coincé sur cette question pendant longtemps en suivant tous les différents remèdes en vain.

J'ai remarqué que lors de l'ajout d'une barre oblique [/] à la fin de l'URL contenant les points [.], Cela n'a pas généré d'erreur 404 et cela a réellement fonctionné.

J'ai finalement résolu le problème en utilisant un réécriveur d'URL comme IIS URL Rewrite pour surveiller un modèle particulier et ajouter la barre oblique de formation.

Mon URL ressemble à ceci: /Contact/~firstname.lastname donc mon modèle est tout simplement: /Contact/~(.*[^/[)$

J'ai eu cette idée de Scott Forsyth, voir le lien ci-dessous: http://weblogs.asp.net/owscott/handing-mvc-paths-with-dots-in-the-path

Leon van Wyk
la source
Cela a fonctionné pour moi (MVC5). Les autres suggestions ci-dessus n'ont pas fonctionné et n'étaient pas nécessaires, juste une barre oblique de fin. Je vais changer mes itinéraires comme suggéré par @ jonduncan05 ici .
markau
Merci, Léon. J'ai sauvé la journée pour moi. Je ne suis pas sûr de tous les trucs web.config dont les gens parlent ici, mais l'ajout de la fin / était la réponse dont j'avais besoin. Dans mon cas, j'ai le contrôle sur le contrôleur côté serveur et le javascript qui l'appelait, donc je viens de mettre à jour le JavaScript et le tour est joué!
Frog Pr1nce
21

Ajoutez simplement cette section à Web.config, et toutes les demandes à la route / {* pathInfo} seront traitées par le gestionnaire spécifié, même s'il y a des points dans pathInfo. (extrait de l'exemple Web.config de l'hôte ServiceStack MVC et de cette réponse https://stackoverflow.com/a/12151501/801189 )

Cela devrait fonctionner pour IIS 6 et 7. Vous pouvez affecter des gestionnaires spécifiques à différents chemins après la «route» en modifiant path = "*" dans les éléments «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
la source
2
Méfiez-vous des conséquences sur les performances de runAllManagedModulesForAllRequests (RAMMFAR). Cela activera tous les modules gérés pour chaque demande. Les fichiers statiques, tels que les images, peuvent être traités directement par IIS, mais cela les traite via chaque module, ajoutant une surcharge à chaque demande.
Mark
@Des marques. oui, mais je pense que cela n'affectera que la demande de routage / ... si nous utilisons la section <location> et ne définissons pas les runAllManagedModulesForAllRequests dans la section principale <system.webServer>.
VB
@VB Je pense que le gestionnaire suffit, sauf si vous avez sur le système des fichiers qui correspondent à une URL que .NET est censé traiter. Et pour une raison quelconque, RAMMFAR ne fonctionnait pas au niveau <location>, mais la solution de gestion l'a fait.
webXL
@webXL <location> nécessaire lorsque vous ne voulez pas que MVC traite les demandes vers une route spécifiée et ajoute des routes.IgnoreRoute ("route / {* pathInfo}"); Ensuite, IIS examinera la section d'emplacement <location path = "route"> et utilisera les gestionnaires spécifiés dans la section d'emplacement, mais il contournera complètement le routage de MVC et les autres étapes du pipeline de MVC. Dans mon projet, l'API ServiceStack ne fonctionne tout simplement pas sans cette configuration.
VB
Pourquoi l'ajout du gestionnaire ne fonctionne-t-il pas simplement? Dans mon cas, je dois ajouter RAMMFAR avec le gestionnaire. Vous cherchez une bonne explication ici. :)
Aditya Patil
6

Solution de contournement MVC 5.0.

La plupart des réponses suggérées ne semblent pas fonctionner dans MVC 5.0.

Comme le problème des 404 points dans la dernière section peut être résolu en fermant cette section avec une barre oblique, voici le petit truc que j'utilise, propre et simple.

Tout en gardant un espace réservé pratique à votre avis:

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

ajoutez un peu de jquery / javascript pour faire le travail:

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

veuillez noter la barre oblique de fin, qui est responsable du changement

http://localhost:51003/GeoData/Manage/[email protected]

dans

http://localhost:51003/GeoData/Manage/[email protected]/
Luc
la source
5

Réponse super simple pour ceux qui ne l'ont que sur une seule page Web. Modifiez votre lien d'action et un + "/" à la fin de celui-ci.

  @Html.ActionLink("Edit", "Edit", new { id = item.name + "/" }) |
Jeremy Hobbs
la source
Résolu pour moi! Simple et élégant! Le plus irritant est qu'il fonctionne sans le «/» sur Windows 10 pendant le développement, mais pour Windows 2012, cela semble nécessaire.
Wim ten Brink
2

Vous voudrez peut-être penser à utiliser des tirets au lieu de points.

Dans Pro ASP MVC 3 Framework, ils suggèrent de créer des URL conviviales:

Évitez les symboles, les codes et les séquences de caractères. Si vous voulez un séparateur de mots, utilisez un tiret (/ mon-grand-article). Les traits de soulignement sont hostiles et les espaces encodés URL sont bizarres (/ mon + grand + article) ou dégoûtant (/ mon% 20great% 20article).

Il mentionne également que les URL doivent être faciles à lire et à modifier pour les humains. Peut-être une raison de penser à utiliser un tiret au lieu d'un point vient également du même livre:

N'utilisez pas d'extensions de noms de fichiers pour les pages HTML (.aspx ou .mvc), mais utilisez-les pour des types de fichiers spécialisés (.jpg, .pdf, .zip, etc.). Les navigateurs Web ne se soucient pas des extensions de nom de fichier si vous définissez le type MIME de manière appropriée, mais les humains s'attendent toujours à ce que les fichiers PDF se terminent par .pdf

Donc, même si une période est toujours lisible par les humains (bien que moins lisible que les tirets, IMO), elle peut toujours être un peu déroutante / trompeuse selon ce qui vient après la période. Et si quelqu'un a un nom de famille de zip? L'URL sera alors /John.zip au lieu de / John-zip, ce qui peut être trompeur même pour le développeur qui a écrit l'application.

sdm350
la source
Il s'agit probablement d'un nom d'utilisateur ou d'un autre champ qui contient intrinsèquement des points. Cela dit, StackOverflow remplace toutes les ponctuations (y compris .) par des tirets dans ses URL utilisateur: P
jli
J'ai rencontré cela parce que j'ai un service de récupération de fichiers sécurisé qui contient évidemment des noms de fichiers dans le paramètre route ...
FlavorScape
Voté pour la raison évidente: il ne répond pas à la question. Si je le pouvais, je ne laisserais pas les points apparaître dans mon URL. Ils apparaissent, car l'URL est générée et doit être lisible par l'homme.
mg30rg
2

Selon l'importance pour vous de conserver votre URI sans chaîne de requête, vous pouvez également simplement passer la valeur avec des points dans le cadre de la chaîne de requête, pas l'URI.

Par exemple, www.example.com/people?name=michael.phelps fonctionnera, sans avoir à modifier les paramètres ou quoi que ce soit.

Vous perdez l'élégance d'avoir un URI propre, mais cette solution ne nécessite pas de modifier ou d'ajouter des paramètres ou des gestionnaires.

GR7
la source
1

Serait-il possible de modifier la structure de votre URL?
Pour ce que je travaillais, j'ai essayé un itinéraire pour

url: "Download/{fileName}"

mais il a échoué avec tout ce qui avait un. en elle.

J'ai changé de route pour

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

Maintenant, je peux mettre localhost:xxxxx/File1.doc/Downloadet ça fonctionne bien.

Mes assistants dans la vue l'ont également remarqué

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

qui fait également un lien vers le localhost:xxxxx/File1.doc/Downloadformat.

Vous pourriez peut-être mettre un mot inutile comme "/ vue" ou une action à la fin de votre itinéraire afin que votre propriété puisse se terminer par /quelque chose comme/mike.smith/view

jonduncan05
la source
1

C'est aussi simple que de changer path = " ." à path = " ". Supprimez simplement le point dans le chemin pour ExensionlessUrlHandler-Integrated-4.0 dans web.config.

Voici un bel article https://weblog.west-wind.com/posts/2015/Nov/13/Serving-URLs-with-File-Extensions-in-an-ASPNET-MVC-Application

Jonny
la source
Ce lien m'a conduit à la meilleure solution à mon problème (le segment contient un caractère "." Mais les clients ne suivront pas avec un "/"). Corrigé en ayant cette ligne dans <system.webServer> de web.config - <modules runAllManagedModulesForAllRequests = "true" />
NickBeaugié
1

J'ai essayé toutes les solutions ci-dessus, mais aucune n'a fonctionné pour moi. Ce qui a fonctionné, c'est que j'ai désinstallé les versions .NET> 4.5, y compris toutes ses versions multilingues; Finalement, j'ai ajouté des versions plus récentes (en anglais uniquement) pièce par pièce. À l'heure actuelle, les versions installées sur mon système sont les suivantes:

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

Et ça fonctionne toujours à ce stade. J'ai peur d'installer 4.6.2 car cela pourrait tout gâcher.

Je ne pouvais donc que spéculer que la version 4.6.2 ou toutes ces versions non anglaises perturbaient ma configuration.

jokab
la source
0

J'ai pu résoudre ma version particulière de ce problème (j'ai dû faire le chemin /customer.html vers / client, les barres obliques de fin ne sont pas autorisées) en utilisant la solution à https://stackoverflow.com/a/13082446/1454265 et en remplaçant le chemin = "*. html".

user1454265
la source
0

Comme solution, on pourrait également envisager de coder dans un format qui ne contient pas de symbole ., comme base64.

Dans js doit être ajouté

btoa(parameter); 

Dans le contrôleur

byte[] bytes = Convert.FromBase64String(parameter);
string parameter= Encoding.UTF8.GetString(bytes);
Max Booreviy
la source
0

Ajoutez la règle de réécriture d'URL à l'archive Web.config. Vous devez avoir le module de réécriture d'URL déjà installé dans IIS. Utilisez la règle de réécriture suivante comme source d'inspiration pour la vôtre.

<?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> 
Amadeus Sánchez
la source
0

Vérifiez également (en rapport) l'ordre de vos mappages de gestionnaires. Nous avions un .ashx avec un .svc (par exemple /foo.asmx/bar.svc/path) dans le chemin suivant. Le mappage .svc était d'abord 404 pour le chemin .svc qui correspondait avant le .asmx. Je n'ai pas trop réfléchi mais peut-être que l'URL encodant le chemin s'en occuperait.

stuartm9999
la source
-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");
        }
    }
}
hamyari afarinesh
la source
1
Comment cela répond-il à la question d'OP? Voulez-vous le décrire s'il vous plaît?
kayess
ce n'est pas une solution, c'est un hack qui nécessite que l'extension du fichier soit placée dans le chemin uri (sans point) par exemple "~ / Image / jpg / cow" pour récupérer le fichier "/ app_data / images / cow / jpg" - - pas la solution que ce mec et tous les autres trouvent ce besoin.
Shaun Wilson