Bagaimana cara mengatur cookie pada HttpClient's HttpRequestMessage

246

Saya mencoba menggunakan api web HttpClientuntuk melakukan posting ke titik akhir yang memerlukan login dalam bentuk cookie HTTP yang mengidentifikasi akun (ini hanya sesuatu yang sudah #ifdefdihapus dari versi rilis).

Bagaimana cara menambahkan cookie ke HttpRequestMessage?

George Mauer
sumber

Jawaban:

374

Inilah cara Anda dapat menetapkan nilai cookie khusus untuk permintaan:

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
sumber
2
handler dapat dihapus dari menggunakan pernyataan, itu akan dibuang ketika klien http dibuang.
Kimi
17
Kimi benar, tetapi Anda juga tidak harus membungkus HttpClient Anda saat menggunakan. aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong
Robert McLaws
9
PERHATIAN: jika Anda hanya menggunakan 1 instance HttpClient untuk melakukan beberapa permintaan, cookie menggunakan CookieContainer akan di-cache. Berbahaya bagi pengguna mendapatkan cookie dari pengguna lain.
Acaz Souza
31
"HttpClient dimaksudkan untuk dipakai satu kali dan digunakan kembali sepanjang masa aplikasi. Terutama dalam aplikasi server, membuat instance HttpClient baru untuk setiap permintaan akan menghabiskan jumlah soket yang tersedia di bawah beban berat ..." Dari sini: asp .net / web-api / ikhtisar / lanjutan / ...
SergeyT
4
@SergeyT jadi apa yang dilakukan seseorang ketika dia perlu membuat panggilan sesi terpisah ke sumber yang sama? :)
AgentFire
336

The jawabannya diterima adalah cara yang benar untuk melakukan hal ini dalam banyak kasus. Namun, ada beberapa situasi di mana Anda ingin mengatur header cookie secara manual. Biasanya jika Anda menetapkan tajuk "Cookie" itu diabaikan, tetapi itu karena HttpClientHandlerdefault untuk menggunakan CookieContainerpropertinya untuk cookie. Jika Anda menonaktifkannya maka dengan menyetel UseCookieske falseAnda dapat mengatur header cookie secara manual dan mereka akan muncul dalam permintaan, misalnya

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
sumber
44
Saya telah mengejar selama beberapa hari kesalahan di mana permintaan yang dikirim dengan SendAsync tidak mengirim header cookie; ini membantu saya menyadari bahwa, kecuali jika Anda menetapkan UseCookies = false di Handler, itu tidak hanya akan menggunakan CookieContainer, tetapi juga secara diam-diam mengabaikan Cookie yang disimpan dalam header permintaan! Terima kasih banyak!
Fernando Neira
14
Jawaban ini sangat membantu bagi siapa pun yang mencoba menggunakan HttpClient sebagai proxy!
cchamberlain
3
Cobalah ini sekarang ... jika berhasil ... Anda pantas mendapatkan pelukan Kanada yang bagus.
Maxime Rouiller
11
PERHATIAN: jika Anda hanya menggunakan 1 instance HttpClient untuk melakukan beberapa permintaan, cookie menggunakan CookieContainer akan di-cache. Berbahaya bagi pengguna mendapatkan cookie dari pengguna lain.
Acaz Souza
9
Benda bodoh itu harus mengeluarkan pengecualian ketika seseorang mencoba menambahkan header "Cookie" alih-alih diam-diam melepaskannya. Habiskan satu jam hidup saya. Terima kasih atas solusinya.
stmax
5

Setelah menghabiskan berjam-jam untuk masalah ini, tidak ada jawaban di atas yang membantu saya, jadi saya menemukan alat yang sangat berguna.

Pertama, saya menggunakan Telerik's Fiddler 4 untuk mempelajari Permintaan Web saya secara detail

Kedua, saya menemukan plugin yang berguna untuk Fiddler ini:

https://github.com/sunilpottumuttu/FiddlerGenerateHttpClientCode

Itu hanya akan menghasilkan kode C # untuk Anda. Contohnya adalah:

        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;

Perhatikan bahwa saya harus mengomentari dua baris karena plugin ini belum sepenuhnya sempurna tetapi ia tetap bekerja.

PENOLAKAN: Saya tidak terkait atau didukung oleh Telerik atau penulis plugin.

Amir No-Family
sumber
2
Ini pada dasarnya adalah jawaban yang sama dengan yang ini , satu -satunya bagian dari itu yang ada hubungannya dengan cookie adalah penambahan header yang terakhir. Perhatikan semua peringatan dalam jawaban itu
George Mauer
4

Bagi saya solusi sederhana berfungsi untuk mengatur cookie di objek 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
sumber
Perhatikan bahwa jawaban yang diterima melakukan ton lebih dan menangani kondisi tepi lebih banyak dari ini. Hal ini dapat digunakan untuk melakukan hal-hal seperti http saja atau scoped cookies, multivalue cookies, dll dll Jawabannya kedua nilai tertinggi mengusulkan metode yang sama seperti ini tetapi dengan lebih banyak konteks dan penjelasan
George Mauer
@ GeorgeMauer mungkin Anda benar. Keduanya membuat httpClient dari "HttpClient (handler)". Dalam kasus saya, saya membuat _httpClient dari httpClientPool.GetOrCreateHttpClient ()
Waqar UlHaq
1
Tetapi Anda tidak benar-benar menunjukkan bahwa dalam jawaban Anda juga tidak menjelaskan perbedaan atau manfaatnya (itu juga sebenarnya bukan pertanyaannya, tetapi saya tidak khawatir tentang itu). Saya tidak berusaha bersikap kasar, hanya penting untuk memperjelas siapa jawaban ini akan membantu yang tidak akan lebih baik ditolong oleh yang lain.
George Mauer