.net UrlEncode - проблема со строчными буквами

Я работаю над передачей данных для шлюза, который требует от меня отправки данных в форме UrlEncoded. Однако UrlEncode .net создает теги в нижнем регистре и прерывает передачу (Java создает верхний регистр).

Есть мысли, как я могу заставить .net выполнять UrlEncoding в верхнем регистре?

update1:

.net out:

dltz7UK2pzzdCWJ6QOvWXyvnIJwihPdmAioZ%2fENVuAlDQGRNCp1F

против Java:

dltz7UK2pzzdCWJ6QOvWXyvnIJwihPdmAioZ%2FENVuAlDQGRNCp1F

(это строка base64d 3DES, мне нужно сохранить ее случай).


person balint    schedule 27.05.2009    source источник
comment
Какая строка ввода для вывода, который вы показываете?   -  person Fredrik Mörk    schedule 28.05.2009
comment
@Fredrik: Кодировка URL-адреса возвращает исходную строку с недопустимыми символами, замененными на% xx, где xx - шестнадцатеричное значение недопустимого символа в ISO-8859-1. Следовательно, отображается исходная строка, но с изменением% 2F на символ '/'.   -  person Kevin    schedule 28.05.2009
comment
+1 Спасибо, что задали этот вопрос. Ответ мне помог. Эта проблема вызвала у меня много головной боли.   -  person jessegavin    schedule 26.05.2011
comment
Это большой вопрос! Я знаю, что это старый, но ответ @ GreysonTyrus на сегодняшний день самый простой - просто используйте WebUtility.UrlEncode.   -  person Dr. C. Hilarius    schedule 23.07.2016


Ответы (7)


Я думаю, вы застряли в том, что дает вам C #, а появление ошибок предполагает, что на другом конце плохо реализована функция UrlDecode.

С учетом сказанного вам просто нужно перебрать строку и прописными буквами только два символа, следующие за знаком%. Это сохранит ваши данные base64 нетронутыми, в то время как закодированные символы будут преобразованы в правильный формат:

public static string UpperCaseUrlEncode(string s)
{
  char[] temp = HttpUtility.UrlEncode(s).ToCharArray();
  for (int i = 0; i < temp.Length - 2; i++)
  {
    if (temp[i] == '%')
    {
      temp[i + 1] = char.ToUpper(temp[i + 1]);
      temp[i + 2] = char.ToUpper(temp[i + 2]);
    }
  }
  return new string(temp);
}
person Kevin    schedule 27.05.2009
comment
спасибо, но вопрос был скорее о соответствии и реализации RFC. - person balint; 28.05.2009
comment
@balint, соответствующие RFC говорят, что вы можете использовать верхний или нижний регистр для экранированных символов в URL-адресе, поэтому ошибки с нижним регистром предполагают плохую реализацию на стороне декодирования. Однако приведенный выше код C # даст те же результаты, что и UrlEncode Java, поэтому, если я не понимаю вопрос, это должно быть именно то, что вам нужно. - person Kevin; 28.05.2009
comment
Несмотря на то, что спецификация говорит, что это нормально, это все равно имеет огромное значение, когда закодированная строка является частью ввода в процедуру хеширования :-( - person Tim Jarvis; 24.07.2009
comment
Спасибо, меня это злило. Я пытался сделать простую проверку подписи (SAML2), и я не заметил строчных символов. - person Gaucho; 06.06.2012
comment
Это актуально для меня, поскольку я использую HMAC. Мне потребовалось целых два часа, чтобы обнаружить тонкую разницу, из-за которой это у меня не получилось. - person frostymarvelous; 13.03.2014
comment
У меня была проблема, аналогичная @frostymarvelous, мне нужно было сгенерировать подпись HMAC для остальной части строки запроса, и хотя URI не чувствительны к регистру, HMAC чувствительны. Согласно RFC 3986, шестнадцатеричные коды в верхнем и нижнем регистре допустимы в процентном кодировании (это означает, что серверы и браузеры должны принимать и то, и другое), но для согласованности рекомендуется использовать верхний регистр. - person KeithS; 20.01.2016
comment
У JW Player api такая же проблема - person dvdmn; 03.06.2017

Я знаю, что он очень старый и, возможно, этого решения не существовало, но это была одна из лучших страниц, которые я нашел в Google, когда пытался решить эту проблему.

System.Net.WebUtility.UrlEncode(posResult);

Это кодируется в верхнем регистре.

person GreysonTyrus    schedule 13.10.2015
comment
Подтверждено, что это наиболее простое решение. - person JTW; 12.07.2016
comment
Я пробовал, но вот проблема с (и) они после кодирования остаются, но должны быть% 28 и% 29. Как решить эту проблему? - person Sharunas Bielskis; 16.07.2016

Замените строчную процентную кодировку из HttpUtility.UrlEncode на Regex:

static string UrlEncodeUpperCase(string value) {
    value = HttpUtility.UrlEncode(value);
    return Regex.Replace(value, "(%[0-9a-f][0-9a-f])", c => c.Value.ToUpper());
}

var value = "SomeWords 123 #=/ äöü";

var encodedValue = HttpUtility.UrlEncode(value);
// SomeWords+123+%23%3d%2f+%c3%a4%c3%b6%c3%bc

var encodedValueUpperCase = UrlEncodeUpperCase(value);
// now the hex chars after % are uppercase:
// SomeWords+123+%23%3D%2F+%C3%A4%C3%B6%C3%BC
person Martin Meixger    schedule 16.12.2009

Это очень просто

Regex.Replace( encodedString, @"%[a-f\d]{2}", m => m.Value.ToUpper() )

Т.е. заменить все шестнадцатеричные буквенно-цифровые комбинации на верхний регистр

person SeregaKa    schedule 19.02.2015
comment
не должно быть% [\ da-f] {2} - person Konstantin Ershov; 08.11.2019

если кто-то еще попадет сюда в поисках кода perl или PCRE (регулярного выражения, совместимого с perl), чтобы решить проблему, (кандидатом на кратчайшее возможное) выражение perl для преобразования кодировки URL в шестнадцатеричный формат нижнего регистра будет:

s/%(\X{2})/%\L$1\E/go

и наоборот (строчные буквы в верхний регистр)

s/%(\x{2})/%\U$1\E/go
person Nils Goroll    schedule 07.02.2013

Это код, который я использую в приложении Twitter для OAuth ...

    Public Function OAuthUrlEncode(ByVal value As String) As String
    Dim result As New StringBuilder()
    Dim unreservedChars As String = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.~"
    For Each symbol As Char In value
        If unreservedChars.IndexOf(symbol) <> -1 Then
            result.Append(symbol)
        Else
            result.Append("%"c + [String].Format("{0:X2}", AscW(symbol)))
        End If
    Next

    Return result.ToString()
End Function

Надеюсь это поможет!

person DWRoelands    schedule 28.07.2009
comment
имейте в виду, что код (OAuthUrlEncode) в ответе DWRoelands вызовет у вас проблемы с международными символами! - person Dov; 13.10.2009
comment
Будьте осторожны с этим. Это вызовет проблемы с международными символами. Например, попробуйте закодировать это: õ. System.Web.HttpUtility.UrlEncode (õ) вернет правильный% c3% b5, но ваш метод вернет% F5. И при публикации этого сообщения как обновления статуса Twitter, Twitter будет возвращать эту ошибку: {errors: [{code: 91, message: Один или несколько параметров содержат недопустимую последовательность UTF-8}]} - person Johnny Oshika; 09.07.2013

Вот мой VB.NET преобразование общедоступной OAuth.OAuthBase версии UrlEncode (для .NET 2.0 / 3.5):

' MEH: Made this ReadOnly because the range of unreserved characters is specified in the OAuth spec. Inheritors ought not change it.
Protected Shared ReadOnly unreservedChars As String = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.~"
' MEH: Added. These are the other characters HttpUtility.UrlEncode does not convert to percent encoding itself.
Protected Shared ReadOnly reservedChars As String = " !'()*" ' If this moves to .NET 4+ ' can be removed.


''' <summary>
''' This is a different Url Encode implementation since the default .NET one outputs the percent encoding in lower case.
''' While this is not a problem with the percent encoding spec, it is used in upper case throughout OAuth.
''' Also the OAuth spec explicitly requires some characters to be unencoded.
''' </summary>
''' <param name="Value">The value to Url encode</param>
''' <returns>Returns a Url encoded string</returns>
''' <revisionhistory>
'''   140313 MEH Fixed to correctly cater for any characters between %80 and %ff, and the O(n^2) IndexOf call.
''' </revisionhistory>
Public Shared Function UrlEncode(ByVal Value As String) As String
    Dim result, buffer As New StringBuilder()

    For Each symbol As Char In Value
        If unreservedChars.IndexOf(symbol) <> -1 Then
            UrlEncodeAppendClear(result, buffer).Append(symbol)
        ElseIf reservedChars.IndexOf(symbol) = -1 Then
            'some symbols produce 2 or more octets in UTF8 so the system urlencoder must be used to get the correct data
            ' but this is best done over a full sequence of characters, so just store this one in a buffer.
            buffer.Append(symbol)
        Else ' These characters are not converted to percent encoding by UrlEncode.
            UrlEncodeAppendClear(result, buffer).AppendFormat(Globalization.CultureInfo.InvariantCulture, "%{0:X2}", AscW(symbol))
        End If
    Next
    UrlEncodeAppendClear(result, buffer)
    Return result.ToString()
End Function


Private Shared percentHex As New RegularExpressions.Regex("(%[0-9a-f][0-9a-f])", RegularExpressions.RegexOptions.Compiled)

''' <summary>
'''  Actually performs the UrlEncode on any buffered characters, ensuring the resulting percents are uppercased and clears the buffer.
''' </summary>
''' 
''' <param name="Result">The result of the UrlEncode is appended here.</param>
''' <param name="Buffer">The current buffer of characters to be encoded. Cleared on return.</param>
''' 
''' <returns>The <paramref name="Result">Result</paramref>, as passed in, with the UrlEncoding of the <paramref name="Buffer">buffer of characters</paramref> appended.</returns>
''' 
''' <remarks>Would like to be an extension method.</remarks>
''' 
''' <revisionhistory>
'''   140313 MEH Created.
''' </revisionhistory>
Private Shared Function UrlEncodeAppendClear(ByVal Result As StringBuilder, ByVal Buffer As StringBuilder) As StringBuilder
    If Buffer.Length > 0 Then
        Result.Append(percentHex.Replace(HttpUtility.UrlEncode(Buffer.ToString), Function(c) c.Value.ToUpperInvariant()))
        Buffer.Length = 0
    End If
    Return Result
End Function
person Mark Hurd    schedule 03.09.2014