2009-02-26 26 views
54

Mi mapa es:barra URL codificada en URL

routes.MapRoute(
    "Default",            // Route name 
    "{controller}/{action}/{id}",       // URL with params 
    new { controller = "Home", action = "Index", id = "" } // Param defaults 
); 

Si utilizo la URL http://localhost:5000/Home/About/100%2f200 no hay ninguna ruta coincidente. Cambio la URL a http://localhost:5000/Home/About/100 y la ruta vuelve a coincidir.

¿Hay alguna manera fácil de trabajar con parámetros que contienen barras inclinadas? Otros valores escapados (espacio %20) parecen funcionar.

EDIT:

para codificar base 64 funciona para mí. Hace que la URL sea fea, pero está bien por ahora.

public class UrlEncoder 
{ 
    public string URLDecode(string decode) 
    { 
     if (decode == null) return null; 
     if (decode.StartsWith("=")) 
     { 
      return FromBase64(decode.TrimStart('=')); 
     } 
     else 
     { 
      return HttpUtility.UrlDecode(decode) ; 
     } 
    } 

    public string UrlEncode(string encode) 
    { 
     if (encode == null) return null; 
     string encoded = HttpUtility.PathEncode(encode); 
     if (encoded.Replace("%20", "") == encode.Replace(" ", "")) 
     { 
      return encoded; 
     } 
     else 
     { 
      return "=" + ToBase64(encode); 
     } 
    } 

    public string ToBase64(string encode) 
    { 
     Byte[] btByteArray = null; 
     UTF8Encoding encoding = new UTF8Encoding(); 
     btByteArray = encoding.GetBytes(encode); 
     string sResult = System.Convert.ToBase64String(btByteArray, 0, btByteArray.Length); 
     sResult = sResult.Replace("+", "-").Replace("/", "_"); 
     return sResult; 
    } 

    public string FromBase64(string decode) 
    { 
     decode = decode.Replace("-", "+").Replace("_", "/"); 
     UTF8Encoding encoding = new UTF8Encoding(); 
     return encoding.GetString(Convert.FromBase64String(decode)); 
    } 
} 

EDIT1:

Al final resultó que era la mejor manera de ahorrar una cadena muy bien formateado para cada artículo que necesito para seleccionar. Eso es mucho mejor porque ahora solo codigo valores y nunca los decodifico. Todos los caracteres especiales se convierten en "-". Muchas de mis tablas db ahora tienen esta columna adicional "URL". La información es bastante estable, por eso puedo ir por este camino. Incluso puedo verificar si los datos en "URL" son únicos.

Edit2:

También ten cuidado con carácter de espacio. Se ve bien en VS servidor web integrado, pero es diferente en iis7 Properly url encode space character

+2

También podría encontrar alguna otra forma de enmascarar la barra, por ejemplo, reemplazarla por otra cosa por convención. Lo sé. Eso es feo también, pero al menos la URL permanece algo legible. – Tomalak

+2

Noté que las barras diagonales y los puntos me dan errores.Hice una ayuda rápida que los reemplaza con "-slash-" y "-dot-". Me pregunto por qué el Url.Encode/Decode no funciona. Además, ¿por qué un personaje escapado estaría dando algún error? –

+7

Esto no es un problema de codificación con el enrutamiento; aparentemente es un error en la clase .NET Uri. De acuerdo con [mi lectura de] URI RFC, las barras diagonales codificadas en la ruta no deben considerarse separadores de segmentos. El enrutamiento MVC no tiene la posibilidad de hacerlo bien porque la clase Uri (incorrectamente) decodifica las barras antes de que el enrutamiento lo vea. Ver la sección 2.2 y 2.4 del RFC. http://labs.apache.org/webarch/uri/rfc/rfc3986.html#reserved –

Respuesta

44

Si es sólo el último parámetro, se puede hacer:

routes.MapRoute(
    "Default",            // Route name 
    "{controller}/{action}/{*id}",       // URL with parameters 
    new { controller = "Home", action = "Index", id = "" }); // Parameter defaults 
+1

Gracias, buena respuesta :) –

+0

No me siento cómodo haciendo esto como una práctica general, especialmente en un sitio web público, pero hice esto en una aplicación web de intranet y no me siento demasiado culpable al respecto. ¡Gracias por señalar esta solución! – jkade

+7

@jkade (o alguien más) ¿por qué no te sientes cómodo con esto en un sitio web público? – wal

10

Otra opción es utilizar un valor cadena de consulta. Muy cojo, pero más simple que la codificación personalizada.

http://localhost:5000/Home/About?100%2f200 
+0

Buena llamada, Jon. Esta es la única forma segura que se me ocurre. Rompe un poco la convención, pero resuelve el problema cuando tu ID tiene que ser una cadena de caracteres. –

+0

No creo que esto sea cojo, creo que es la mejor opción, pero creo que tu ejemplo está equivocado. Debería ser -/Acerca de? X = 100% 2f200 - ¿no? – niico

23

En .NET 4.0 beta 2, el equipo de CLR ha ofrecido una solución alternativa.

Agregar a su archivo web.config:

<uri> 
    <schemeSettings> 
     <add name="http" genericUriParserOptions="DontUnescapePathDotsAndSlashes" /> 
    </schemeSettings> 
</uri> 

Esto hace que la clase Uri a comportarse de acuerdo con el RFC que describe URI, lo que permite barras que se escapó en el camino sin ser sin escapar. El equipo de CLR informa que se desvía de la especificación por razones de seguridad, y establecer esto en su archivo .config básicamente le hace tomar posesión de las consideraciones de seguridad adicionales involucradas en no desamarrar las barras inclinadas.

+0

Esto suena genial. Usaré esto como la respuesta una vez que se lanza .NET 4.0. –

+4

Esto no funciona. Obtiene subrayados azules en Visual Studio y parece no tener ningún efecto. – cdmckay

+10

Nota: A partir del lanzamiento oficial de .NET 4, [MSDN] (http://msdn.microsoft.com/en-us/library/ee656542.aspx) indica que esta configuración solo se puede agregar a machine.config o application.config - NO es el web.config. –

0

Eso es interesante sobre .NET 4. De todos modos, este enlace describe RFC 1738 e incluye qué caracteres necesitan codificación y cuáles son simplemente "inseguros". link text

Si quiero una URL amigable con SEO, (como cuando quiere poner un tema de publicación en el foro en la URL), omita la codificación y reemplace cualquier cosa que no sea A-Z, a-z, 0-9.

public static string CreateSubjectSEO(string str) 
    { 
     int ci; 
     char[] arr = str.ToCharArray(); 
     for (int i = 0; i < arr.Length; i++) 
     { 
      ci = Convert.ToInt32(arr[i]); 
      if (!((ci > 47 && ci < 58) || (ci > 64 && ci < 91) || (ci > 96 && ci < 123))) 
      { 
       arr[i] = '-'; 
      } 
     } 
     return new string(arr); 
    } 
9

Lo mismo para Java/Tomcat.

Todavía hay un problema si tiene un "/" codificado (% 2F) en su URL.

RFC 3986 - Sección 2.2 dice: "Si los datos de un componente de URI entrarían en conflicto con el propósito de un carácter reservado como delimitador, entonces los datos en conflicto deben estar codificados porcentualmente antes de que se forme el URI". (RFC 3986 - Sección 2.2)

Pero hay un problema con Tomcat:

http://tomcat.apache.org/security-6.html - Fixed in Apache Tomcat 6.0.10

important: Directory traversal CVE-2007-0450

Tomcat permits '\', '%2F' and '%5C' [...] .

The following Java system properties have been added to Tomcat to provide additional control of the handling of path delimiters in URLs (both options default to false):

  • org.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH: true|false
  • org.apache.catalina.connector.CoyoteAdapter.ALLOW_BACKSLASH: true|false

Due to the impossibility to guarantee that all URLs are handled by Tomcat as they are in proxy servers, Tomcat should always be secured as if no proxy restricting context access was used.

Affects: 6.0.0-6.0.9

Así que si usted tiene una dirección URL con el carácter% 2F, Tomcat vuelve: "400 URI no válido: noSlash"

se puede cambiar de la corrección de errores en la secuencia de comandos de inicio de Tomcat:

set JAVA_OPTS=%JAVA_OPTS% %LOGGING_CONFIG% -Dorg.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH=true 
20

Aquí hay una explicación sencilla de la solución y la suma de lo que ya se ha dicho.

lado Solicitud:

  1. UrlEncode de su camino.
  2. Reemplace el '%' con '!'.
  3. Haga la solicitud. lado

Respuesta:

  1. Sustituir el '!' con '%'.
  2. UrlDecode your path.
  3. Use los parámetros como estaban destinados.

Enjuague, repita, disfrute.

+1

Puede, como a mí, también encontrarse con este problema: Error de aplicación: la longitud de la URL para esta solicitud excede el valor maxUrlLength configurado. se puede resolver mediante la adición de este valor web.config: \t \t

+1

simple y eficaz! Gracias. – nrod

+0

escriba mejor su propio servidor web – Toolkit

-1

Como sugirió here cuando el problema se enfrentó por los desarrolladores Symfony 1.x (+ sugeridos en PHP comments for urlencode()):

  • Codificar '/' a '% 2F' antes urlencode()
  • Decode '% 2F' a '/' después (si es necesario) urldecode()

Nota: se puede usar rawurlencode(), pero todavía tendrá que urlencode '/' dos veces.

Ventajas:

  • evita la necesidad de procesos que escapan adicionales ('!' Si va a cambiar '/' con un carácter especial como o '_')
  • ¿No se basa en cualquier servidor de la escena como AllowEncodedSlashes para Apache
+0

Esto no funciona con ASP.NET 4. Aún dice HTTP Error 400 - Solicitud incorrecta. – Rn222

+0

Lo siento si esta respuesta es para PHP/Apache. Supongo que debería aplicarse el mismo tipo de lógica para ASP.NET. Tal vez alguien tendrá tiempo para "traducirlo" para ASP.NET antes que yo. Dejo mi respuesta porque creo que puede ayudar, incluso si las tecnologías utilizadas son diferentes (como @simonox answer) –

-3

Solo use Server.UrlDecode. Funcionará, lo he probado.

+0

UrlDecoding no es el problema aquí, es el enrutamiento dentro de MVC y el hecho de que las cadenas codificadas con barras (% 2f) se analizará en el enrutamiento como si fueran (% 2f) son parte de la url. – Rodi

1

Puede evitar las sugerencias de codificación doble/decodificación anteriores y simplemente usar HttpServerUtility.UrlTokenEncode y el correspondiente UrlTokenDecode.

Cuestiones relacionadas