2016-02-29 59 views
5

我有以下設置:C#如何在一個cookie通過使用共享的HttpClient

JS客戶端 - >網絡API - >網絡API

我需要一路下行發送身份驗證的cookie 。我的問題是從一個網絡API發送到另一個。由於與使用FormsAuthentication的舊系統集成,我必須傳遞auth cookie。

出於性能的原因我在以下詞典共享HttpClients的列表(一個用於每個web API):

private static ConcurrentDictionary<ApiIdentifier, HttpClient> _clients = new ConcurrentDictionary<ApiIdentifier, HttpClient>(); 

所以給定的標識符我可以抓住對應的HttpClient。

下面的作品,但我敢肯定,這是不好的代碼:

HttpClient client = _clients[identifier]; 
var callerRequest = HttpContext.Current.Items["MS_HttpRequestMessage"] as HttpRequestMessage; 
string authCookieValue = GetAuthCookieValue(callerRequest); 

if (authCookieValue != null) 
{ 
    client.DefaultRequestHeaders.Remove("Cookie"); 
    client.DefaultRequestHeaders.Add("Cookie", ".ASPXAUTH=" + authCookieValue); 
} 

HttpResponseMessage response = await client.PutAsJsonAsync(methodName, dataToSend); 

// Handle response... 

請告訴我錯了,這是:1)它似乎是錯誤的操縱請求DefaultRequestHeaders; 2)潛在的2個simultanious請求可能會混淆cookie,因爲HttpClient是共享的。

我一直在尋找一段時間沒有找到解決方案,因爲大多數有匹配的問題實例化每個請求的HttpClient,因此能夠設置所需的標題,我試圖避免。

有一次,我得到了使用HttpResponseMessage的請求。也許這對解決方案有啓發作用。

所以我的問題是:有沒有一種方法可以爲使用HttpClient的單個請求設置Cookie,這對於使用相同實例的其他客戶端來說是安全的?

回答

11

而不是調用PutAsJsonAsync(),您可以使用HttpRequestMessage和SendAsync()的:

Uri requestUri = ...; 
HttpMethod method = HttpMethod.Get /*Put, Post, Delete, etc.*/; 
var request = new HttpRequestMessage(method, requestUri); 
request.Headers.TryAddWithoutValidation("Cookie", ".ASPXAUTH=" + authCookieValue); 
request.Content = new StringContent(jsonDataToSend, Encoding.UTF8, "application/json"); 
var response = await client.SendAsync(request); 

UPDATE: 爲了確保您的HTTP客戶端不會儲存你需要做的這個響應的Cookie:

var httpClient = new HttpClient(new HttpClientHandler() { UseCookies = false; }); 

否則,如果您使用一個客戶端並共享其他cookie,您可能會收到意想不到的行爲。

+0

非常感謝!看起來我已經非常接近了,但是你已經超越了終點。一個問題:是否有可能讓GET請求使用stringcontent?如果我的'jsonDataToSend'是一個複雜的對象,它不會傳遞它,但如果我自己將它轉換爲查詢字符串並將它作爲'method'傳遞它就可以工作。將很高興有一個通用的方法:) – Casper

+0

np :)通常GET不包含正文,但它不被規範禁止。你可以使用'new ObjectContent (value,new JsonMediaTypeFormatter(),「application/json」)'而不是'StringContent' –