Web API缓存HttpMessage内容报错,如何正确实现HttpMessage缓存?
问题描述
我想在Web API中缓存部分数据,但遇到了错误。我使用HttpContent并通过CacheHelper.SaveToCache将其存入缓存。在后续请求时,我检查缓存中是否存在该内容,若存在则创建新的HttpRequestMessage并设置其HttpContent,但出现了错误。
错误信息
Error: read ECONNRESET
This site can’t be reached
控制器代码
public class UserDataController : ApiController { [System.Web.Http.HttpGet] public IHttpActionResult GetUser(string accessKey, string id) { DateTime cacheDuration = DateTime.Now.AddSeconds(cacheDurationTime); string cacheKey = String.Format("{0}_{1}", accessKey, id); if (CacheHelper.GetObjectFromCach(cacheKey) != null){ var cacheContent = CacheHelper.GetFromCache<HttpContent>(cacheKey); var response = this.Request.CreateResponse(HttpStatusCode.OK); response.Content = cacheContent; return ResponseMessage(response); else { var Results = User.UserFromId(id); CacheHelper.SaveToCache(cacheKey, Results.Content, cacheDuration); return ResponseMessage(Results); } } }
助手类代码
public static void SaveToCache(string cacheKey, object savedItem, DateTime absoluteExpiration) { MemoryCache.Default.Add(cacheKey, savedItem, absoluteExpiration); } public static T GetFromCache<T>(string cacheKey) where T : class { return MemoryCache.Default[cacheKey] as T; }
请问该如何缓存HttpMessage的内容?
解决方案
问题根源是直接缓存HttpContent对象:HttpContent是流式对象,首次返回响应时其内部流会被读取并关闭,后续无法重复读取,这就是触发ECONNRESET错误的原因。正确做法是缓存内容的原始数据,而非HttpContent对象本身。
具体修改步骤
- 缓存时提取并序列化内容:读取
HttpContent的字符串或字节数组形式,存入缓存,不要直接缓存HttpContent。 - 读取缓存时重建
HttpContent:从缓存中取出序列化数据,用它新建StringContent或ByteArrayContent对象,再赋值给响应。
修改后的代码示例
控制器代码
public class UserDataController : ApiController { [System.Web.Http.HttpGet] public async Task<IHttpActionResult> GetUser(string accessKey, string id) { int cacheDurationTime = 30; // 可根据实际调整缓存时长 DateTime cacheDuration = DateTime.Now.AddSeconds(cacheDurationTime); string cacheKey = $"{accessKey}_{id}"; var cachedContent = CacheHelper.GetFromCache<string>(cacheKey); if (cachedContent != null) { var response = Request.CreateResponse(HttpStatusCode.OK); // 根据实际内容类型调整媒体类型,示例为JSON response.Content = new StringContent(cachedContent, Encoding.UTF8, "application/json"); return ResponseMessage(response); } else { var results = User.UserFromId(id); // 读取HttpContent内容并存入缓存 string contentStr = await results.Content.ReadAsStringAsync(); CacheHelper.SaveToCache(cacheKey, contentStr, cacheDuration); return ResponseMessage(results); } } }
助手类代码无需修改
额外优化方案
如果返回的是复杂业务对象,也可以直接缓存对象本身,读取时再序列化:
// 缓存对象 var userData = await results.Content.ReadAsAsync<User>(); CacheHelper.SaveToCache(cacheKey, userData, cacheDuration); // 读取缓存时序列化 var cachedUser = CacheHelper.GetFromCache<User>(cacheKey); response.Content = new StringContent(JsonConvert.SerializeObject(cachedUser), Encoding.UTF8, "application/json");
注意事项
- 确保缓存键的唯一性,避免不同请求内容互相覆盖;
- 根据返回内容的类型(文本/二进制)选择缓存字符串或字节数组。
内容的提问来源于stack exchange,提问作者Jefferson
相关产品推荐
相关产品推荐

