使用WebClient作为代理时如何原样返回远程服务器的所有响应?
实现方案
你当前的代码会将远程服务返回的响应字符串反序列化为JObject对象后再返回,会破坏原始响应结构,同时也没有透传响应头、HTTP状态码等信息,不符合透传需求,按如下修改即可:
基于现有WebClient的修改方案
如果要保留WebClient的写法,直接去掉JObject转换逻辑,同时按需透传响应头即可:
using (var client = new WebClient()) { client.Headers[HttpRequestHeader.ContentType] = "application/json"; Uri NODE_LOGIN_PATH = new Uri(URI_Combine(NodeAPI, "auth/login")); string jsonString = JsonConvert.SerializeObject(login_details); // 直接获取原始响应字符串,不做任何序列化/反序列化处理 string rawResponseBody = await client.UploadStringTaskAsync(NODE_LOGIN_PATH, jsonString); // 如需透传响应头,遍历WebClient的ResponseHeaders添加到当前接口的响应中即可 foreach (string headerKey in client.ResponseHeaders.AllKeys) { // 以ASP.NET为例:Response.Headers.Add(headerKey, client.ResponseHeaders[headerKey]); } // 原样返回原始响应内容 return rawResponseBody; }
注意:WebClient默认遇到非2xx状态码会抛出WebException,你不需要处理异常的话直接不捕获即可,异常会原样向上抛出,符合透传要求。
更推荐的HttpClient实现方案
WebClient属于.NET平台过时的API,更推荐用HttpClient实现透传,处理响应头、状态码更灵活,性能也更好:
// 注意:HttpClient不要每次请求都实例化,建议全局单例或者依赖注入获取 private static readonly HttpClient _httpClient = new HttpClient(); public async Task<IActionResult> ProxyLoginAsync() { var request = new HttpRequestMessage(HttpMethod.Post, new Uri(URI_Combine(NodeAPI, "auth/login"))) { Content = new StringContent(JsonConvert.SerializeObject(login_details), Encoding.UTF8, "application/json") }; // 发送请求,不对响应做提前处理 var remoteResponse = await _httpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead); // 透传状态码 Response.StatusCode = (int)remoteResponse.StatusCode; // 透传所有响应头 foreach (var header in remoteResponse.Headers) { Response.Headers.TryAdd(header.Key, header.Value.ToArray()); } foreach (var contentHeader in remoteResponse.Content.Headers) { Response.Headers.TryAdd(contentHeader.Key, contentHeader.Value.ToArray()); } // 直接透传响应流,不需要转成字符串,性能更高 var responseStream = await remoteResponse.Content.ReadAsStreamAsync(); return new FileStreamResult(responseStream, remoteResponse.Content.Headers.ContentType?.ToString() ?? "application/json"); }
内容的提问来源于stack exchange,提问作者Wing Shum
相关产品推荐
相关产品推荐

