URI . escapedatastring() -无效URI: URI字符串太长

本文关键字:URI 字符串 escapedatastring 无效 | 更新日期: 2023-09-27 18:02:40

我在windows mobile上使用compact framework/c#。

在我的应用程序中,我通过序列化对象和使用HttpWebRequest/POST请求将信息发送到服务器上传数据。在服务器上,post数据被反序列化并保存到数据库中。

前几天我意识到我在帖子数据(&等)中的特殊字符有问题。因此,我将Uri.EscapeDataString()引入方法,一切顺利。

然而,今天我发现有一个问题,当应用程序试图上传大量的数据(我不确定究竟什么是"大"的时刻!)

现有代码(类)

var uploadData = new List<Things>();
uploadData.Add(new Thing() { Name = "Test 01" });
uploadData.Add(new Thing() { Name = "Test 02" });
uploadData.Add(new Thing() { Name = "Test with an & Ampersand " }); // Do this a lot!!
var postData = "uploadData=" + Uri.EscapeDataString(JsonConvert.SerializeObject(uploadData, new IsoDateTimeConverter()));

对Uri.EscapeDataString()的调用导致以下异常:

系统。UriFormatException: Invalid URI: URI字符串太长。

还有其他的方法来准备上传的数据吗?

据我所知,HttpUtility(它有自己的Encode/Decode方法)不适用于紧凑框架。

URI . escapedatastring() -无效URI: URI字符串太长

或者您可以简单地拆分字符串并为每个块调用Uri.EscapeDataString(string),以避免重新实现该函数。

示例代码:

        String value = "large string to encode";
        int limit = 2000;
        StringBuilder sb = new StringBuilder();
        int loops = value.Length / limit;
        for (int i = 0; i <= loops; i++)
        {
            if (i < loops)
            {
                sb.Append(Uri.EscapeDataString(value.Substring(limit * i, limit)));
            }
            else
            {
                sb.Append(Uri.EscapeDataString(value.Substring(limit * i)));
            }
        }

"Alberto de Paola"的答案是好的。

尽管如此,要对转义的数据进行反转义有点棘手,因为您必须避免在已编码的字符中间切割已编码的字符串(否则您将破坏原始字符串的完整性)。

这是我解决这个问题的方法:

public static string EncodeString(string str)
{
    //maxLengthAllowed .NET < 4.5 = 32765;
    //maxLengthAllowed .NET >= 4.5 = 65519;
    int maxLengthAllowed = 65519;
    StringBuilder sb = new StringBuilder();
    int loops = str.Length / maxLengthAllowed;
    for (int i = 0; i <= loops; i++)
    {
        sb.Append(Uri.EscapeDataString(i < loops
            ? str.Substring(maxLengthAllowed * i, maxLengthAllowed)
            : str.Substring(maxLengthAllowed * i)));
    }
    return sb.ToString();
}
public static string DecodeString(string encodedString)
{
    //maxLengthAllowed .NET < 4.5 = 32765;
    //maxLengthAllowed .NET >= 4.5 = 65519;
    int maxLengthAllowed = 65519;
    int charsProcessed = 0;
    StringBuilder sb = new StringBuilder();
    while (encodedString.Length > charsProcessed)
    {
        var stringToUnescape = encodedString.Substring(charsProcessed).Length > maxLengthAllowed
            ? encodedString.Substring(charsProcessed, maxLengthAllowed)
            : encodedString.Substring(charsProcessed);
        // If the loop cut an encoded tag (%xx), we cut before the encoded char to not loose the entire char for decoding
        var incorrectStrPos = stringToUnescape.Length == maxLengthAllowed ? stringToUnescape.IndexOf("%", stringToUnescape.Length - 4, StringComparison.InvariantCulture) : -1;
        if (incorrectStrPos > -1)
        {
            stringToUnescape = encodedString.Substring(charsProcessed).Length > incorrectStrPos
                ? encodedString.Substring(charsProcessed, incorrectStrPos)
                : encodedString.Substring(charsProcessed);
        }
        sb.Append(Uri.UnescapeDataString(stringToUnescape));
        charsProcessed += stringToUnescape.Length;
    }
    var decodedString = sb.ToString();
    // ensure the string is sanitized here or throw exception if XSS / SQL Injection is found
    SQLHelper.SecureString(decodedString);
    return decodedString;
}

测试这些函数:

var testString = "long string to encode";
var encodedString = EncodeString(testString);
var decodedString = DecodeString(encodedString);
Console.WriteLine(decodedString == testString ? "integrity respected" : "integrity broken");

StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < originalString.Length; i++)
{
    if ((originalString[i] >= 'a' && originalString[i] <= 'z') || 
        (originalString[i] >= 'A' && originalString[i] <= 'Z') || 
        (originalString[i] >= '0' && originalString[i] <= '9'))
    {
        stringBuilder.Append(originalString[i]);
    }
    else
    {
        stringBuilder.AppendFormat("%{0:X2}", (int)originalString[i]);
    }
}
string result = stringBuilder.ToString();

我一直在使用system . web . httutility . urlencode,似乎处理较长的字符串要好得多。

使用System.Web.HttpUtility.UrlEncode(基于此答案):

        value = HttpUtility.UrlEncode(value)
            .Replace("!", "%21")
            .Replace("(", "%28")
            .Replace(")", "%29")
            .Replace("*", "%2A")
            .Replace("%7E", "~"); // undo escape

我需要另一种解决方案,因为Pouki的解决方案在处理西里尔字母和切割符号时不起作用。

另一种解决方案如下:

    protected const int MaxLengthAllowed = 32765;
    private static string UnescapeString(string encodedString)
    {
        var charsProccessed = 0;
        var sb = new StringBuilder();
        while (encodedString.Length > charsProccessed)
        {
            var isLastIteration = encodedString.Substring(charsProccessed).Length < MaxLengthAllowed;
            var stringToUnescape = isLastIteration
                ? encodedString.Substring(charsProccessed)
                : encodedString.Substring(charsProccessed, MaxLengthAllowed);
            while (!Uri.IsWellFormedUriString(stringToUnescape, UriKind.RelativeOrAbsolute) || stringToUnescape.Length == 0)
            {
                stringToUnescape = stringToUnescape.Substring(0, stringToUnescape.Length - 1);
            }
            sb.Append(Uri.UnescapeDataString(stringToUnescape));
            charsProccessed += stringToUnescape.Length;
        }
        return sb.ToString();
    }