¿Cómo configuro una cookie en el HttpRequestMessage de HttpClient?

246

Estoy tratando de usar la API web HttpClientpara hacer una publicación en un punto final que requiere iniciar sesión en forma de una cookie HTTP que identifica una cuenta (esto es solo algo que está #ifdeffuera de la versión de lanzamiento).

¿Cómo agrego una cookie a la HttpRequestMessage?

George Mauer
fuente

Respuestas:

374

A continuación, le mostramos cómo puede establecer un valor de cookie personalizado para la solicitud:

var baseAddress = new Uri("http://example.com");
var cookieContainer = new CookieContainer();
using (var handler = new HttpClientHandler() { CookieContainer = cookieContainer })
using (var client = new HttpClient(handler) { BaseAddress = baseAddress })
{
    var content = new FormUrlEncodedContent(new[]
    {
        new KeyValuePair<string, string>("foo", "bar"),
        new KeyValuePair<string, string>("baz", "bazinga"),
    });
    cookieContainer.Add(baseAddress, new Cookie("CookieName", "cookie_value"));
    var result = await client.PostAsync("/test", content);
    result.EnsureSuccessStatusCode();
}
Darin Dimitrov
fuente
2
el controlador puede eliminarse de la declaración de uso, se eliminará cuando se elimine el cliente http.
Kimi
17
Kimi es correcto, pero tampoco debe envolver su HttpClient en un uso. aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong
Robert McLaws
99
PRECAUCIÓN: si usa solo 1 instancia de HttpClient para hacer varias solicitudes, las cookies que usan CookieContainer se almacenarán en caché. Es peligroso para un usuario obtener la cookie de otro usuario.
Acaz Souza
31
"HttpClient está destinado a ser instanciado una vez y reutilizado durante la vida útil de una aplicación. Especialmente en aplicaciones de servidor, crear una nueva instancia de HttpClient para cada solicitud agotará la cantidad de sockets disponibles bajo cargas pesadas ..." Desde aquí: asp .net / web-api / overview / advanced / ...
SergeyT
44
@SergeyT, entonces, ¿qué hace uno cuando necesita hacer llamadas de sesión separada al mismo recurso? :)
AgentFire
336

La respuesta aceptada es la forma correcta de hacer esto en la mayoría de los casos. Sin embargo, hay algunas situaciones en las que desea configurar el encabezado de la cookie manualmente. Normalmente, si configura un encabezado "Cookie", se ignora, pero eso se debe HttpClientHandleral uso predeterminado de su CookieContainerpropiedad para cookies. Si deshabilita que a continuación mediante el establecimiento UseCookiesde falseque se pueden establecer cabeceras de cookies de forma manual y aparecerán en la solicitud, por ejemplo,

var baseAddress = new Uri("http://example.com");
using (var handler = new HttpClientHandler { UseCookies = false })
using (var client = new HttpClient(handler) { BaseAddress = baseAddress })
{
    var message = new HttpRequestMessage(HttpMethod.Get, "/test");
    message.Headers.Add("Cookie", "cookie1=value1; cookie2=value2");
    var result = await client.SendAsync(message);
    result.EnsureSuccessStatusCode();
}
Greg Beech
fuente
44
He estado persiguiendo durante varios días un error en el que las solicitudes enviadas con SendAsync no enviaron el encabezado de la cookie; ¡Esto me ayudó a darme cuenta de que, a menos que establezca UseCookies = false en el controlador, no solo usará el Contenedor de cookies, sino que también ignorará en silencio cualquier cookie almacenada en los encabezados de solicitud! Muchas gracias!
Fernando Neira
14
¡Esta respuesta es extremadamente útil para cualquiera que intente usar HttpClient como proxy!
cchamberlain
3
Intentando esto ahora ... si funciona ... te mereces un buen abrazo canadiense.
Maxime Rouiller
11
PRECAUCIÓN: si usa solo 1 instancia de HttpClient para hacer varias solicitudes, las cookies que usan CookieContainer se almacenarán en caché. Es peligroso para un usuario obtener la cookie de otro usuario.
Acaz Souza
99
Esa estupidez debería arrojar una excepción cuando alguien intenta agregar un encabezado "Cookie" en lugar de perderlo en silencio. Me costó una hora de mi vida. Gracias por la solucion.
stmax
5

Después de pasar horas en este tema, ninguna de las respuestas anteriores me ayudó, así que encontré una herramienta realmente útil.

En primer lugar, utilicé el Fiddler 4 de Telerik para estudiar en detalle mis solicitudes web

En segundo lugar, me encontré con este complemento útil para Fiddler:

https://github.com/sunilpottumuttu/FiddlerGenerateHttpClientCode

Simplemente generará el código C # para usted. Un ejemplo fue:

        var uriBuilder = new UriBuilder("test.php", "test");
        var httpClient = new HttpClient();


        var httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, uriBuilder.ToString());



        httpRequestMessage.Headers.Add("Host", "test.com");
        httpRequestMessage.Headers.Add("Connection", "keep-alive");
     //   httpRequestMessage.Headers.Add("Content-Length", "138");
        httpRequestMessage.Headers.Add("Pragma", "no-cache");
        httpRequestMessage.Headers.Add("Cache-Control", "no-cache");
        httpRequestMessage.Headers.Add("Origin", "test.com");
        httpRequestMessage.Headers.Add("Upgrade-Insecure-Requests", "1");
    //    httpRequestMessage.Headers.Add("Content-Type", "application/x-www-form-urlencoded");
        httpRequestMessage.Headers.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36");
        httpRequestMessage.Headers.Add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8");
        httpRequestMessage.Headers.Add("Referer", "http://www.translationdirectory.com/");
        httpRequestMessage.Headers.Add("Accept-Encoding", "gzip, deflate");
        httpRequestMessage.Headers.Add("Accept-Language", "en-GB,en-US;q=0.9,en;q=0.8");
        httpRequestMessage.Headers.Add("Cookie", "__utmc=266643403; __utmz=266643403.1537352460.3.3.utmccn=(referral)|utmcsr=google.co.uk|utmcct=/|utmcmd=referral; __utma=266643403.817561753.1532012719.1537357162.1537361568.5; __utmb=266643403; __atuvc=0%7C34%2C0%7C35%2C0%7C36%2C0%7C37%2C48%7C38; __atuvs=5ba2469fbb02458f002");


        var httpResponseMessage = httpClient.SendAsync(httpRequestMessage).Result;

        var httpContent = httpResponseMessage.Content;
        string result = httpResponseMessage.Content.ReadAsStringAsync().Result;

Tenga en cuenta que tuve que comentar dos líneas, ya que este complemento aún no es totalmente perfecto, pero de todos modos hizo el trabajo.

DESCARGO DE RESPONSABILIDAD: no estoy asociado ni respaldado por Telerik ni por el autor del complemento de ninguna manera.

Amir No-Family
fuente
2
Esta es esencialmente la misma respuesta que esta , la única parte que tiene que ver con las cookies es la última adición de un encabezado. Tenga en cuenta todas las advertencias en esa respuesta
George Mauer,
4

Para mí, la solución simple funciona para establecer cookies en el objeto HttpRequestMessage .

protected async Task<HttpResponseMessage> SendRequest(HttpRequestMessage requestMessage, CancellationToken cancellationToken = default(CancellationToken))
{
    requestMessage.Headers.Add("Cookie", $"<Cookie Name 1>=<Cookie Value 1>;<Cookie Name 2>=<Cookie Value 2>");

    return await _httpClient.SendAsync(requestMessage, cancellationToken).ConfigureAwait(false);
}
Waqar UlHaq
fuente
Tenga en cuenta que la respuesta aceptada hace mucho más y maneja muchas más condiciones de borde que esto. Se puede usar para hacer cosas como solo http o cookies de alcance, cookies de valores múltiples, etc. La segunda respuesta mejor calificada propone el mismo método pero con mucho más contexto y explicación
George Mauer,
@GeorgeMauer puede ser que tengas razón. Ambos creando httpClient desde "HttpClient (manejador)". En mi caso, estoy creando _httpClient desde httpClientPool.GetOrCreateHttpClient ()
Waqar UlHaq
1
Pero en realidad no muestra eso en su respuesta ni explica la diferencia o los beneficios (tampoco es realmente la pregunta, pero eso no me preocupa). No estoy tratando de ser grosero, es importante tener claro a quién sería útil esta respuesta para que los demás no la ayudaran mejor.
George Mauer