You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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对象本身。

具体修改步骤

  1. 缓存时提取并序列化内容:读取HttpContent的字符串或字节数组形式,存入缓存,不要直接缓存HttpContent。
  2. 读取缓存时重建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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 16:53:15