Додавання заголовків HttpClient генерує FormatException з деякими значеннями


83

Це сталося в контексті кодування проти Google Cloud Messaging, але застосовується деінде.

Розглянемо наступне:

var http = new HttpClient();
http.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("key=XXX");

і

var http = new HttpClient();
http.DefaultRequestHeaders.Add("Authorization", "key=XXX");

обидва з яких генерують FormatException:

System.FormatException: недійсний формат значення значення = XXX '.

Рішення полягає у видаленні знака рівності.

  1. Поглиблення у рефлектор показує, що існує безліч кодів перевірки та синтаксичного аналізу, який запускається при додаванні нового значення заголовка. Навіщо все це потрібно? Чи не повинен цей клієнт просто ухилятися від нашого шляху?

  2. Як уникнути знака рівності, щоб додавання цього значення вдалося?


@SamIam намагається опублікувати повідомлення в API GCN - що вимагає надсилання інформації про автентичність у вигляді заголовка у форматі, показаному вище. Однак це більш загальне питання щодо дозволених значень для заголовків HttpClient.
Ендрю

Відповіді:


176

Не впевнений, чи все ще актуальний, але нещодавно я зіткнувся з цією ж проблемою і зміг її вирішити, викликавши інший метод для додавання інформації заголовка:

var http = new HttpClient();
http.DefaultRequestHeaders.TryAddWithoutValidation("Authorization", "key=XXX");

2
ви також можете викликати цей метод на HttpRequestMessage, якщо не хочете його використовувати в заголовках за замовчуванням
Ед Сайкс

8
Позначив це як відповідь, хоча я все ще не розумію, чому інший метод не працює під час перевірки, якщо це дійсне значення.
Ендрю

1
Крім того, здається, це не допомагає в httpclient для Windows 10
Sinaesthetic

4
Я бачу, що це стара тема, але я щойно зіткнувся з цим питанням @EdSykes і спробував HttpRequestMessageнатомість використовувати, і це не мало ніякої різниці. TryAddWithoutValidationМетод зробив трюк для мене.
Метью Блотт,

23

Відповідь на ваше запитання "навіщо все це (аналіз та перевірка)" відповідає: це визначено в стандарті HTTP.

У HTTP / 1.1 та RFC2617 значення заголовка автентифікації (наприклад, WWW-Аутентифікація та Авторизація) складається з двох частин: частини схеми та частини параметра .

Для HTTP Basic Authentication схема є "Basic", а параметром може бути щось на зразок "QWxhZGRpbjpvcGVuIHNlc2FtZQ ==" , тому весь заголовок стає:

Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==

Ось чому ваш "ключ = XXX" не проходить перевірку, оскільки йому не вистачає частини схеми.


Наявність ключа = значення в розділі параметрів є дійсним. Див. Stackoverflow.com/a/19512506/55732 .
Джон Курлак

1
@Kurlak: ключ = значення дійсне лише для частини "auth-param", а не для всієї частини "облікові дані". Інтерпретація CodeCaster не зовсім правильна.
Террі Чанг

3
Я фактично використовую Bearerяк схему, але вона все ще показує мені помилку.
Том

1
У мене був пробіл після Носія, наприклад "Носій", який викликав проблеми. Я побачив відповідь @Robert Stokes нижче, яка допомогла мені це побачити.
Шанті

7

Я обійшов цей виняток (мій FormatException, спричинений комами у значенні), встановивши заголовок авторизації наступним чином:

var authenticationHeaderValue = new AuthenticationHeaderValue("some scheme", "some value");
client.DefaultRequestHeaders.Authorization = authenticationHeaderValue;

4

Я зіткнувся з цією помилкою і наткнувся на цю публікацію, коли додав пробіл у кінці заголовка авторизації.

this.bearerAuthHttpClient.DefaultRequestHeaders.Add("Authorization ", $"Bearer {token}");

Ви можете побачити "" правопорушник після "Авторизації.

У мене пішло близько 15 хв, перш ніж я побачив свою помилку ...


1

Сьогодні вранці я пережив кілька запитань, маючи справу із зовнішнім API, який не відповідає специфікаціям HTTP.

Як частина мого розміщення, вони хочуть Content-Typeі Content-Disposition, який не можна додати до HttpClientоб’єкта. Щоб додати ці заголовки, вам потрібно створити HttpRequestMessage . Там вам потрібно додати заголовки до Contentвластивості.

private HttpRequestMessage GetPostMessage(string uri, string contentType,
                                          string fileName, Stream content)
{    
    var request = new HttpRequestMessage
    {
        Content = new StreamContent(content),
        RequestUri = new Uri(uri),
        Method = HttpMethod.Post
    };

    // contentType = "video/mp4"
    request.Content.Headers.ContentType = new MediaTypeHeaderValue(contentType);

    //Need TryAddWithoutValidation because of the equals sign in the value.
    request.Content
           .Headers
           .TryAddWithoutValidation("Content-Disposition",
                                    $"attachment; filename=\"{Path.GetFileName(fileName)}\"");

    // If there is no equals sign in your content disposition, this will work:
    // request.Content.Headers.ContentDisposition = 
    //    new ContentDispositionHeaderValue($"attachment; \"{Path.GetFileName(fileName)}\"");

    return request;
}

0

У моєму випадку я генерую значення рядків ETags з байтового [] поля SQL RowVersion. Тому мені потрібно додати wrap згенерованого. тобто AAAAAAAAF5s = рядок всередині "наступним чином ...

        var eTag = department.RowVersion.ToETagString();

        httpClient.DefaultRequestHeaders.Add(Microsoft.Net.Http.Headers.HeaderNames.IfMatch, $"\"{eTag}\"")


    public class DepartmentForHandleDto
    {
        public string Name { get; set; }
        public string GroupName { get; set; }
        public byte[] RowVersion { get; set; }
    }

    public static class ByteArrayExtensions
    {
        public static string ToETagString(this byte[] byteArray)
        {
            return Convert.ToBase64String(byteArray != null && byteArray.Length > 0 ? byteArray : new byte[8]);                    
        }
    }
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.