ChatGPT解决这个技术问题 Extra ChatGPT

Adding HttpClient headers generates a FormatException with some values

This occurred within the context of coding against Google Cloud Messaging, but applies elsewhere.

Consider the following:

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

and

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

both of which generate a FormatException:

System.FormatException : The format of value key=XXX' is invalid.

The solution is to remove the equals sign.

Digging into reflector shows there is oodles of validation and parsing code that runs when adding a a new header value. Why is all this necessary? Shouldn't this client just be getting out of our way? How do you escape the equals sign so that adding this value succeeds?

@SamIam trying to post a message to the GCN API - which requires auth info to be sent as a header using the format shown above. However, this is a more general question around the permitted values for HttpClient headers.

A
Antonio

Not sure if still relevant, but I recently ran into this same issue and was able to solve it by calling a different method to add the header information:

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

you can also call this method on HttpRequestMessage if you don't want it in the default headers
Marked this as the answer, even though I still don't understand why the other method is failing on validation if it's a valid value.
Also, doesn't seem to help in Windows 10's httpclient
I see this is an old thread but I've just ran into this issue @EdSykes and tried using HttpRequestMessage instead and it made no difference. The TryAddWithoutValidation method did the trick for me.
My problem was about User-Agent header but thanks for pointing to TryAddWithoutValidation.
G
Guanxi

To your "why is all this (parsing and validation) necessary" question, the answer is: it is defined in the HTTP standard.

In HTTP/1.1 and RFC2617, the value an authentication header (such as WWW-Authenticate and Authorization) has two parts: a scheme part, and a parameter part.

For HTTP Basic Authentication, the scheme is "Basic", and the parameter may be something like "QWxhZGRpbjpvcGVuIHNlc2FtZQ==", so the whole header becomes:

Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==

That's why your "key=XXX" doesn't pass validation, because it lacks a scheme part.


Having key=value in the parameter section is valid. See stackoverflow.com/a/19512506/55732.
@Kurlak: key=value is valid for the "auth-param" part only, not for the whole "credentials" part. CodeCaster's interpretation is not quite right.
I'm actually using Bearer as scheme, but it's still showing me the error.
I had a space after Bearer like "Bearer " which was causing issues. I saw @Robert Stokes answer below that helped me see it.
key=XXX might not be valid, but it's still what Google Firebase API expects from you :(( Proof: firebase.google.com/docs/cloud-messaging/…
R
Robert Stokes

I ran into this error and stumbled on to this post when I added a space to the end of an Authorization header.

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

You can see the offending " " after Authorization.

It took me about 15 min before I saw my typo...


C
CRice

I got around this exception (my FormatException caused by commas in the value) by setting the Authorization header in the following way:

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

k
krillgar

I've been going through a few questions this morning while dealing with an external API that doesn't follow the HTTP spec to the letter.

As part of my posting, they want the Content-Type and Content-Disposition, which cannot be added to the HttpClient object. To add those headers, you need to create an HttpRequestMessage. On there, you need to add the headers to the Content property.

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;
}

a
alhpe

In my case I am generating ETags string values from a byte[] RowVersion SQL field. So I need to add wrap the generated. i.e. AAAAAAAAF5s= string inside " as follows...

        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]);                    
        }
    }