讲师中心 微信公众号
AI工具推荐 视频效率加速

如何使用Golang实现代理缓存系统_Golang代理模式请求优化示例

陌伟小哥_4045

陌伟小哥_4045

发布时间:2026-01-24 10:27:34

|

290人浏览过

|

来源于php中文网

原创

直接用 http.Transport 做代理缓存会失败,因其默认不缓存响应,且 RoundTripper 接口无法拦截并缓存响应体,多次读取 resp.Body 会导致“read on closed response body”错误。

如何使用golang实现代理缓存系统_golang代理模式请求优化示例

为什么直接用 http.Transport 做代理缓存会失败

Go 标准库的 http.Transport 默认不缓存响应,即使你设置了 Cache-Control: public, max-age=3600,它也不会自动复用。更关键的是,http.RoundTripper 接口不暴露原始请求头/响应体,无法在中间拦截并写入本地缓存。常见错误是试图在 RoundTrip 方法里读取 resp.Body 两次——第一次读完后 Body 就被关闭,第二次读会得到空内容或 http: read on closed response body 错误。

  • 必须在读取响应前,用 io.TeeReader 或 io.MultiReader 复制原始字节流
  • 缓存键不能只依赖 req.URL.String(),要归一化:去掉 utm_* 参数、忽略查询参数顺序、统一协议和 host 大小写
  • Cache-Control 中的 no-store、no-cache、private 必须严格跳过缓存

用 http.ServeHTTP 实现可缓存的反向代理

标准库 httputil.NewSingleHostReverseProxy 是起点,但它不支持缓存逻辑注入。你需要继承并重写 Director 和响应处理流程。核心是在 proxy.ServeHTTP 调用后,立即拦截 ResponseWriter,捕获状态码、头信息和响应体。

  • 用 httptest.NewRecorder() 拦截响应,再用 bytes.Buffer 存储原始 body
  • 缓存键生成示例:fmt.Sprintf("%s %s %s", req.Method, normalizeURL(req.URL), req.Header.Get("Accept"))
  • 缓存过期时间优先取 Cache-Control: max-age=N,其次 fallback 到 Expires 头
func (c *cachedProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
    key := c.cacheKey(req)
    if entry, ok := c.cache.Get(key); ok && !entry.Expired() {
        entry.WriteTo(rw)
        return
    }

    resp := httptest.NewRecorder()
    c.proxy.ServeHTTP(resp, req)

    buf := &bytes.Buffer{}
    io.Copy(buf, resp.Body)
    bodyBytes := buf.Bytes()

    cacheEntry := &cacheItem{
        StatusCode: resp.Code,
        Header:     resp.Header().Clone(),
        Body:       bodyBytes,
        CreatedAt:  time.Now(),
        TTL:        c.ttlFromHeaders(resp.Header()),
    }
    c.cache.Set(key, cacheEntry, cacheEntry.TTL)

    rw.WriteHeader(resp.Code)
    for k, vs := range resp.Header() {
        for _, v := range vs {
            rw.Header().Add(k, v)
        }
    }
    rw.Write(bodyBytes)
}

bigcache 或 ristretto 选哪个做内存缓存

bigcache 适合高并发、大量小响应(如 JSON API),因为它用分片 map + 时间戳淘汰,避免 GC 压力;但不支持基于 TTL 的自动过期,得自己轮询清理。ristretto 支持精确 TTL、LRU+LFU 混合策略,更适合混合大小响应(含图片、HTML),但内存占用略高、初始化稍慢。

Feishu calendar sync, local ics to json data for AI agent
Feishu calendar sync, local ics to json data for AI agent

将ICS日历文件转为JSON格式,用于飞书日历导入导出及数据集成。

下载
  • 如果代理目标主要是 REST API(平均响应 bigcache.NewBigCache,设置 Shards: 128
  • 如果需缓存 HTML 或压缩资源(可能 >100KB),用 ristretto.NewCache,开启 OnExit: func(key uint64, value interface{}) 清理大对象
  • 避免用 sync.Map:它不支持容量限制和淘汰,长期运行必然 OOM

如何处理 POST/PUT 请求的缓存穿透

GET 请求天然幂等,可安全缓存;但 POST/PUT 默认不可缓存。若业务明确某些 POST 是只读操作(如 /api/search),需手动放行。关键是识别“语义 GET”:检查路径是否含 search、query、list,且请求体是 JSON 查询条件而非业务变更数据。

立即学习“go语言免费学习笔记(深入)”;

  • 禁止缓存 Content-Type: application/json 且 body 含 "update"、"delete"、"status": "active" 等字段的请求
  • 对放行的 POST,缓存键必须包含 sha256(body),而非仅 URL —— 否则不同查询参数会命中同一缓存
  • 永远不缓存带 Cookie 或 Authorization 头的请求,除非显式配置 CacheableHeaders: ["X-User-ID"]

缓存系统最难的不是存和取,而是判断“该不该缓存”——这个决策点分散在 URL 归一化、头解析、body 检查、TTL 计算多个环节,漏掉任意一个都可能把私有数据缓存成公共响应。

热门AI工具

更多
WorkBuddy

一款AI办公效率工具,主要用于腾讯云推出的AI原生桌面智能体工作台,适合需要提升相关任务效率的用户。

Atoms
Atoms Hot

Atoms是一款AI智能体工具,第一支自动构建真实业务的 AI 团队。

Loomy
Loomy Hot

一款AI工具,主要用于科大讯飞发布的桌面级 AI 助理,比 OpenClaw 更易用、更安全!,适合需要提升相关任务效率的用户。

Lovart
Lovart Hot

一款面向视觉设计创作的AI设计平台,可通过智能体和画布工作流辅助制作海报、Logo、网页、PPT及其他视觉内容。

咔片AIPPT

一款在线AI演示文稿制作工具,可根据主题和内容需求辅助生成PPT结构与页面,提高演示材料制作效率。

讯飞绘文

讯飞绘文是一款由科大讯飞推出的一站式 AIGC 内容运营平台。

UpDream
UpDream Hot

一款AI视频创作工具,主要用于哔哩哔哩推出的自研AI视频创作工具,适合需要提升相关任务效率的用户。

豆包大模型

豆包大模型是一款由字节跳动推出的企业级大语言模型服务平台。

DeepSeek

DeepSeek是一款面向对话、写作、编程和推理场景的AI大模型工具。

相关专题

更多
golang如何定义变量
golang如何定义变量

golang定义变量的方法:1、声明变量并赋予初始值“var age int =值”;2、声明变量但不赋初始值“var age int”;3、使用短变量声明“age :=值”等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

499

2024.02.23

golang有哪些数据转换方法
golang有哪些数据转换方法

golang数据转换方法:1、类型转换操作符;2、类型断言;3、字符串和数字之间的转换;4、JSON序列化和反序列化;5、使用标准库进行数据转换;6、使用第三方库进行数据转换;7、自定义数据转换函数。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

596

2024.02.23

golang常用库有哪些
golang常用库有哪些

golang常用库有:1、标准库;2、字符串处理库;3、网络库;4、加密库;5、压缩库;6、xml和json解析库;7、日期和时间库;8、数据库操作库;9、文件操作库;10、图像处理库。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

1036

2024.02.23

golang和python的区别是什么
golang和python的区别是什么

golang和python的区别是:1、golang是一种编译型语言,而python是一种解释型语言;2、golang天生支持并发编程,而python对并发与并行的支持相对较弱等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

771

2024.03.05

golang是免费的吗
golang是免费的吗

golang是免费的。golang是google开发的一种静态强类型、编译型、并发型,并具有垃圾回收功能的开源编程语言,采用bsd开源协议。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

1526

2024.05.21

golang结构体相关大全
golang结构体相关大全

本专题整合了golang结构体相关大全,想了解更多内容,请阅读专题下面的文章。

4234

2025.06.09

golang相关判断方法
golang相关判断方法

本专题整合了golang相关判断方法,想了解更详细的相关内容,请阅读下面的文章。

1914

2025.06.10

golang数组使用方法
golang数组使用方法

本专题整合了golang数组用法,想了解更多的相关内容,请阅读专题下面的文章。

3846

2025.06.17

LLVM自定义Pass怎么写
LLVM自定义Pass怎么写

本专题聚焦LLVM自定义Pass开发,整理Pass类结构、run()方法、PreservedAnalyses、CMake构建、插件注册、-load-pass-plugin加载和测试用例编写流程。

60

2026.09.30

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
GDB 17.2 官方文档集合
GDB 17.2 官方文档集合

共0课时 | 0人学习

Bootstrap 入门安装配置
Bootstrap 入门安装配置

共0课时 | 0人学习

38+ PhpStorm 提示和技巧
38+ PhpStorm 提示和技巧

共1课时 | 219人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn