9

根据 MSDN

URLEncode 转换字符如下:

  • 空格 ( ) 转换为加号 (+)。
  • 非字母数字字符转义为十六进制表示。

这与W3C相似,但不完全相同

应用程序/x-www-form-urlencoded

这是默认的内容类型。使用此内容类型提交的表单必须编码如下:

  1. 控件名称和值被转义。空格字符被“+”替换,然后保留字符被转义,如RFC1738第 2.2 节所述:非字母数字字符替换为“%HH”、一个百分号和两个表示字符的 ASCII 码的十六进制数字。换行符表示为“CR LF”对(即,'%0D%0A')。

  2. 控件名称/值按照它们在文档中出现的顺序列出。名称与值之间用“=”分隔,名称/值对之间用“&”分隔。

 

我的问题是,有没有人做过确定 URLEncode 是否产生有效的 x-www-form-urlencoded 数据的工作?

4

1 回答 1

6

好吧,您链接到的文档是针对 IIS 6 Server.UrlEncode 的,但您的标题似乎询问了 .NET System.Web.HttpUtility.UrlEncode。使用 Reflector 之类的工具,我们可以看到后者的实现,并确定它是否符合 W3C 规范。

这是最终调用的编码例程(注意,它是为字节数组定义的,其他接受字符串的重载最终将这些字符串转换为字节数组并调用此方法)。您可以为每个控件名称和值调用它(以避免转义= &用作分隔符的保留字符)。

protected internal virtual byte[] UrlEncode(byte[] bytes, int offset, int count)
{
    if (!ValidateUrlEncodingParameters(bytes, offset, count))
    {
        return null;
    }
    int num = 0;
    int num2 = 0;
    for (int i = 0; i < count; i++)
    {
        char ch = (char) bytes[offset + i];
        if (ch == ' ')
        {
            num++;
        }
        else if (!HttpEncoderUtility.IsUrlSafeChar(ch))
        {
            num2++;
        }
    }
    if ((num == 0) && (num2 == 0))
    {
        return bytes;
    }
    byte[] buffer = new byte[count + (num2 * 2)];
    int num4 = 0;
    for (int j = 0; j < count; j++)
    {
        byte num6 = bytes[offset + j];
        char ch2 = (char) num6;
        if (HttpEncoderUtility.IsUrlSafeChar(ch2))
        {
            buffer[num4++] = num6;
        }
        else if (ch2 == ' ')
        {
            buffer[num4++] = 0x2b;
        }
        else
        {
            buffer[num4++] = 0x25;
            buffer[num4++] = (byte) HttpEncoderUtility.IntToHex((num6 >> 4) & 15);
            buffer[num4++] = (byte) HttpEncoderUtility.IntToHex(num6 & 15);
        }
    }
    return buffer;
}

public static bool IsUrlSafeChar(char ch)
{
    if ((((ch >= 'a') && (ch <= 'z')) || ((ch >= 'A') && (ch <= 'Z'))) || ((ch >= '0') && (ch <= '9')))
    {
        return true;
    }
    switch (ch)
    {
        case '(':
        case ')':
        case '*':
        case '-':
        case '.':
        case '_':
        case '!':
            return true;
    }
    return false;
}

例程的第一部分计算需要替换的字符数(空格和非 url 安全字符)。例程的第二部分分配一个新缓冲区并执行替换:

  1. 网址安全字符保持原样:a-z A-Z 0-9 ()*-._!
  2. 空格转换为加号
  3. 所有其他字符都转换为%HH

RFC1738 状态(强调我的):

因此,只有字母数字、特殊字符“$-_.+!*'()”和
用于其保留目的的保留字符可以
在 URL 内未编码使用。

另一方面,不需要编码的
字符(包括字母数字)可以在
URL 的特定于方案的部分中编码,只要它们不被用于保留
目的。

允许的 URL 安全字符UrlEncode集是 RFC1738 中定义的特殊字符的子集。即,字符丢失并且即使规范说它们是安全的$,也会被编码。UrlEncode由于它们可能未编码(而不是must)使用,它仍然符合编码它们的规范(第二段明确说明)。

关于换行符,如果输入有一个CR LF序列,那么它将被转义%0D%0A。但是,如果输入只有LFthen 将被转义%0A(因此在此例程中没有对换行符进行规范化)。

底线:它在额外编码的同时满足规范$,,调用者负责在输入中提供适当规范化的换行符。

于 2011-09-16T18:55:47.577 回答