Pontos no URL causam 404 com o ASP.NET mvc e o IIS

303

Eu tenho um projeto que exige que meus URLs tenham pontos no caminho. Por exemplo, eu posso ter um URL como www.example.com/people/michael.phelps

URLs com o ponto geram um 404. Meu roteamento está bom. Se eu passar em michaelphelps, sem o ponto, tudo funciona. Se eu adicionar o ponto, recebo um erro 404. O site de amostra está sendo executado no Windows 7 com o IIS8 Express. O URLScan não está sendo executado.

Tentei adicionar o seguinte ao meu web.config:

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

Infelizmente isso não fez diferença. Acabei de receber um erro 404.0 não encontrado.

Este é um projeto MVC4, mas não acho relevante. Meu roteamento funciona bem e os parâmetros que eu espero estão lá, até que incluam um ponto.

O que preciso configurar para ter pontos no meu URL?

Marca
fonte
93
Não posso acreditar que passei tanto tempo nisso. O URL funciona bem se eu adicionar uma barra final. Por exemplo, www.example.com/people/michael.phelps/, no entanto, sem a barra final, o IIS gera um erro 404.
Mark
15
Mark - isso ocorre porque, sem a barra final, o IIS acha que é um arquivo que deve ser encontrado. Adicionar a barra tem o efeito de ... este não é um arquivo real. Além disso, a opção de configuração abaixo informa ao IIS que, se não for um arquivo, tente encaminhá-lo.
Tommy
Estou tendo o mesmo problema depois de atualizar meu projeto para o mvc 4 + asp.net 4.5.
Tadeu Maia
Como alternativa, estou usando o IIS Rewrite para adicionar a barra aos meus URLs.
Mark
4
Isso não funciona para mim. O URL funciona bem com "." dentro da URL, mas quando está no final dá um erro
Arcadian

Respostas:

379

Eu consegui isso editando os manipuladores HTTP do meu site. Para minhas necessidades, isso funciona bem e resolve meu problema.

Simplesmente adicionei um novo manipulador HTTP que procura por critérios de caminho específicos. Se a solicitação corresponder, ela será enviada corretamente ao .NET para processamento. Estou muito mais feliz com esta solução que o URLRewrite corta ou habilita o RAMMFAR.

Por exemplo, para o .NET processar a URL www.example.com/people/michael.phelps, adicione a seguinte linha ao web.config do seu site, dentro do system.webServer / handlerselemento:

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

Editar

Há outras postagens sugerindo que a solução para esse problema é RAMMFARou RunAllManagedModulesForAllRequests. A ativação dessa opção ativará todos os módulos gerenciados para todas as solicitações. Isso significa que os arquivos estáticos, como imagens, PDFs e tudo mais, serão processados ​​pelo .NET quando não precisarem. É melhor deixar essas opções, a menos que você tenha um caso específico.

Marca
fonte
3
aqui está um exemplo completo stackoverflow.com/a/16607685/801189 com base nesta resposta
VB
10
depois de adicionar isso com [path = "*"] todas as solicitações para arquivos estáticos, como .css, .js, falham. Eu tenho uma rota personalizada que lida com URLs que se parecem com este " domain / ABCDE.FGHIJ ". Todos os meus arquivos estáticos estão no meu diretório / Content. Existe uma maneira de excluir esse diretório inteiro disso? definir RAMMFAR como true funciona, mas gostaria de evitar essa sobrecarga.
Lamarant
2
O IIS local funciona com a barra inicial, mas o IIS8 entende a rota apenas sem a primeira barra.
Pavel Voronin
2
Estou tendo o mesmo problema que o @lamarant ... Ele bloqueia os arquivos estáticos. Você sabe por quê? Usando MVC4 aqui.
eestein
3
Ele funciona no MVC5, mas se você colocar uma barra no início do caminho, ele funcionará apenas quando o caminho for imediatamente após o nome do host (não é relativo à pasta do aplicativo). Por exemplo, path / people / * funcionaria para www.example.com/people/michael.phelps, mas não para www.example.com/app/people/michael.phelps. AFAIK, não há como fazer o caminho relativo ao aplicativo.
Hogan
46

Após algumas investigações, descobri que o relaxUrlToFileSystemMapping não funcionou para mim, o que funcionou no meu caso foi definir RAMMFAR como true, o mesmo vale para (.net 4.0 + mvc3) e (.net 4.5 + mvc4).

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

Esteja ciente de que ao definir o post verdadeiro de Hanselman sobre RAMMFAR sobre RAMMFAR e desempenho

Tadeu Maia
fonte
5
Esteja ciente de quando a criação RAMMFAR ... Existe alguma perda de desempenho se eu usar isto <módulos runAllManagedModulesForAllRequests = "true">
Shanker Paudel
1
No caso do pôster original, não deve ser necessário, pois ele está usando o IIS7 e superior. Aí está o padrão, e definir o RAMMFAR realmente está custando a você exta. Consulte msdn.microsoft.com/en-us/library/…
Richard
Embora isso seja útil, isso não foi suficiente para obter períodos para parar de retornar 404s no MVC5 / IIS7 para mim.
Chris Moschini 11/01
Só para reiterate.You quer evitar ter essa opção ativada
Strake
Não faça isso em um site ao vivo, se possível.
911 NickG
27

Acredito que você precise definir a propriedade relaxingUrlToFileSystemMapping no seu web.config. Haack escreveu um artigo sobre isso há pouco tempo (e existem outros posts de SO que fazem os mesmos tipos de pergunta)

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

Editar Nos comentários abaixo, as versões posteriores do .NET / IIS podem exigir que isso esteja no system.WebServerelemento

<system.webServer>
<httpRuntime relaxedUrlToFileSystemMapping="true" />
Tommy
fonte
2
Isto é o que eu tive com o mvc3 + .net4.0 e funcionou lindamente, mas não funciona mais com o mvc4 + .net4.5.
Tadeu Maia
4
Eu tentei o relaxUrlToFileSystemMapping sem sucesso. Não acho que funcione com as versões mais recentes do MVC.
Mark
Isso me permitiu pegar o url /WEB-INF./web.xml e redirecioná-lo para uma página de erro personalizada quando muitas outras maneiras pelas quais tentei não funcionaram.
Quentin-starin
3
Interessante. Dado que não funcionou para você, eu estava prestes a assumir que isso não funcionaria para mim ... já que estou no MVC4 com o .NET4.5. Mas o bingo, funcionou de qualquer maneira. No meu caso, eu simplesmente tinha um URL com um período "." como o último caractere. Eu estava recebendo 404, mas isso corrigiu.
PandaWood
Ele tem repercussões na segurança?
precisa saber é o seguinte
23

Fiquei muito tempo preso a esse problema, seguindo todos os remédios diferentes sem sucesso.

Percebi que, ao adicionar uma barra [/] ao final da URL que continha os pontos [.], Não ocorreu um erro 404 e realmente funcionou.

Finalmente, resolvi o problema usando um reescritor de URLs como o IIS URL Rewrite para observar um padrão específico e anexar a barra de treinamento.

Meu URL fica assim: /Contact/~firstname.lastname, portanto, meu padrão é simplesmente: /Contact/~(.*[^/})$

Eu peguei essa ideia de Scott Forsyth, veja o link abaixo: http://weblogs.asp.net/owscott/handing-mvc-paths-with-dots-in-the-path

Leon van Wyk
fonte
Isso funcionou para mim (MVC5). Outras sugestões acima não funcionaram e não eram necessárias, apenas uma barra final. Vou mudar minhas rotas conforme sugerido por @ jonduncan05 aqui .
Markau
Obrigado Leon. Salvou o dia para mim. Não tenho certeza sobre todas as coisas do web.config que as pessoas estão falando aqui, mas adicionar a / final foi a resposta que eu precisava. No meu caso, eu tenho controle sobre o controlador do lado do servidor e o javascript que estava chamando, então atualizei o JavaScript e pronto!
Sapo Pr1nce
21

Basta adicionar esta seção ao Web.config, e todas as solicitações à rota / {* pathInfo} serão tratadas pelo manipulador especificado, mesmo quando houver pontos no pathInfo. (extraído do exemplo do ServiceStack MVC Host Web.config e desta resposta https://stackoverflow.com/a/12151501/801189 )

Isso deve funcionar para o IIS 6 e 7. Você pode atribuir manipuladores específicos a caminhos diferentes após a 'rota', modificando path = "*" nos elementos '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
fonte
2
Cuidado com as conseqüências de desempenho que runAllManagedModulesForAllRequests (RAMMFAR) possui. Isso permitirá que todos os módulos gerenciados para cada solicitação. Arquivos estáticos, como imagens, podem ser processados ​​diretamente pelo IIS, mas isso os processa por todos os módulos, adicionando sobrecarga a cada solicitação.
Mark
@MarkS. sim, mas acredito que isso afetará apenas a solicitação para rotear / ... se usarmos a seção <location> e não definirmos o runAllManagedModulesForAllRequests na seção principal <system.webServer>.
VB
@ BV Acho que apenas o manipulador é suficiente, a menos que você tenha arquivos no sistema que correspondam a uma URL que o .NET deve processar. E por algum motivo, o RAMMFAR não funcionou no nível <location>, mas a solução do manipulador funcionou.
WebXL
@webXL <location> necessário quando você não deseja que o MVC processe solicitações para uma rota especificada e adicione routes.IgnoreRoute ("route / {* pathInfo}"); O IIS examinará a seção de localização <location path = "route"> e usará manipuladores especificados na seção de localização, mas ignorará completamente as etapas de roteamento do MVC e outras etapas do pipeline do MVC. No meu projeto, a API do ServiceStack simplesmente não funciona sem essa configuração.
VB
Por que simplesmente não adicionar o manipulador funciona? No meu caso, eu tenho que adicionar RAMMFAR junto com o manipulador. Procurando uma boa explicação aqui. :)
Aditya Patil
6

Solução alternativa do MVC 5.0.

Muitas das respostas sugeridas não parecem funcionar no MVC 5.0.

Como o problema de 404 pontos na última seção pode ser resolvido fechando-a com uma barra, aqui está o pequeno truque que eu uso, limpo e simples.

Mantendo um espaço reservado conveniente em sua exibição:

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

adicione um pouco de jquery / javascript para fazer o trabalho:

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

observe a barra à direita, responsável pela alteração

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

para dentro

http://localhost:51003/GeoData/Manage/[email protected]/
Lucas
fonte
5

Resposta super fácil para aqueles que só têm isso em uma página da web. Edite seu link de ação e um + "/" no final dele.

  @Html.ActionLink("Edit", "Edit", new { id = item.name + "/" }) |
Jeremy Hobbs
fonte
Resolvi isso para mim! Simples e elegante! O mais irritante é que ele funciona sem o '/' no Windows 10 durante o desenvolvimento, mas para o Windows 2012 parece ser necessário.
Wim ten Brink
2

Você pode pensar em usar traços em vez de pontos.

No Pro ASP MVC 3 Framework, eles sugerem isso sobre como criar URLs amigáveis:

Evite símbolos, códigos e seqüências de caracteres. Se você deseja um separador de palavras, use um traço (/ meu-ótimo-artigo). Os sublinhados não são amigáveis ​​e os espaços codificados por URL são bizarros (/ meu + ótimo + artigo) ou nojentos (/ meu% 20 grande artigo 20).

Ele também menciona que os URLs devem ser fáceis de ler e alterar para humanos. Talvez um motivo para pensar em usar um traço em vez de um ponto também venha do mesmo livro:

Não use extensões de nome de arquivo para páginas HTML (.aspx ou .mvc), mas use-as para tipos de arquivos especializados (.jpg, .pdf, .zip etc.). Os navegadores da Web não se importam com as extensões de nome de arquivo se você definir o tipo MIME adequadamente, mas os humanos ainda esperam que os arquivos PDF terminem com .pdf

Portanto, embora um período ainda seja legível para seres humanos (embora seja menos legível que traços, IMO), ele ainda pode ser um pouco confuso / enganoso, dependendo do que ocorrer após o período. E se alguém tiver um sobrenome zip? Em seguida, o URL será /John.zip em vez de / John-zip, algo que pode ser enganoso até para o desenvolvedor que escreveu o aplicativo.

sdm350
fonte
É provável que um nome de usuário ou outro campo contenha pontos inerentemente. Dito isto, StackOverflow substitui toda a pontuação (incluindo .) com traços em seus urls usuário: P
JLI
Eu encontrei este porque eu tenho serviço de recuperação segura de arquivos que, obviamente, contém nomes de arquivos no parâmetro rota ...
FlavorScape
Votado pela razão óbvia: não responde à pergunta. Se pudesse, não deixaria os períodos aparecerem no meu URL. Eles aparecem porque o URL é gerado e precisa ser legível por humanos.
mg30rg 27/02
2

Dependendo da importância de manter seu URI sem as cadeias de consulta, você também pode passar o valor com pontos como parte da cadeia de consultas, não o URI.

Por exemplo, www.example.com/people?name=michael.phelps funcionará, sem precisar alterar nenhuma configuração ou qualquer coisa.

Você perde a elegância de ter um URI limpo, mas esta solução não requer alteração ou adição de configurações ou manipuladores.

GR7
fonte
1

Seria possível alterar sua estrutura de URL?
Para o que eu estava trabalhando, tentei uma rota para

url: "Download/{fileName}"

mas falhou com qualquer coisa que tivesse um. iniciar.

Mudei a rota para

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

Agora eu posso colocar localhost:xxxxx/File1.doc/Download e funciona bem.

Meus ajudantes na visualização também perceberam

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

que faz um link para o localhost:xxxxx/File1.doc/Download formato também.

Talvez você possa colocar uma palavra desnecessária como "/ view" ou ação no final do seu percurso para que sua propriedade possa terminar com /algo à direita como/mike.smith/view

jonduncan05
fonte
1

É tão simples quanto mudar de caminho = " ." para o caminho = " ". Basta remover o ponto no caminho para ExensionlessUrlHandler-Integrated-4.0 em web.config.

Aqui está um bom artigo https://weblog.west-wind.com/posts/2015/Nov/13/Serving-URLs-with-File-Extensions-in-an-ASPNET-MVC-Application

Jonny
fonte
Esse link me levou à melhor solução para o meu problema (o segmento contém um caractere ".", Mas os clientes não seguem um "/"). Corrigido com esta linha em <system.webServer> do web.config - <módulos runAllManagedModulesForAllRequests = "true" />
NickBeaugié
1

Tentei todas as soluções acima, mas nenhuma delas funcionou para mim. O que funcionou foi desinstalar as versões .NET> 4.5, incluindo todas as suas versões multilíngues; Eventualmente, adicionei versões mais recentes (somente em inglês), peça por peça. No momento, as versões instaladas no meu sistema são:

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

E ainda está trabalhando neste momento. Tenho medo de instalar o 4.6.2, pois pode atrapalhar tudo.

Então, eu só podia especular que 4.6.2 ou todas as versões que não estavam em inglês estavam atrapalhando minha configuração.

jokab
fonte
0

Consegui resolver minha versão específica desse problema (tive que fazer /customer.html direcionar para / customer, não são permitidas barras), usando a solução em https://stackoverflow.com/a/13082446/1454265 e substituindo o caminho = "*. html".

user1454265
fonte
0

Como solução, pode-se considerar também a codificação para um formato que não contém símbolo ., como base64.

Em js deve ser adicionado

btoa(parameter); 

No controlador

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

Adicione a regra de reconfiguração de URL ao arquivo Web.config. Você precisa ter o módulo de reconfiguração de URL já instalado no IIS. Use a seguinte regra de reescrita como inspiração para você.

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

Além disso, verifique a ordem dos seus mapeamentos de manipulador. Tivemos um .ashx com um .svc (por exemplo, /foo.asmx/bar.svc/path) no caminho a seguir. O mapeamento .svc foi o primeiro, 404, para o caminho .svc que correspondia antes do .asmx. Ainda não pensei muito, mas talvez a URL que codifique o caminho resolva isso.

stuartm9999
fonte
-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
fonte
1
Como isso responde à pergunta do OP? Se importa em descrevê-lo, por favor?
kayess
não é uma solução, é um hack que requer que a extensão do arquivo seja colocada no caminho da interface do usuário (sem um ponto), por exemplo, "~ / Image / jpg / cow" para recuperar o arquivo "/ app_data / images / cow / jpg" - - não é a solução que esse cara e todo mundo acham que precisam.
Shaun Wilson