KCloud-Platform-IoT KCloud-Platform-IoT
首页
  • 开发手册

    • 组件【ai】
    • 组件【algorithm】
    • 组件【banner】
    • 组件【core】
    • 组件【bom】
    • 组件【cors】
    • 组件【domain】
    • 组件【crypto】
    • 组件【data-cache】
    • 组件【elasticsearch】
    • 组件【excel】
    • 组件【i18n】
    • 组件【idempotent】
    • 组件【influxdb】
    • 组件【kafka】
    • 组件【log】
    • 组件【lock】
    • 组件【mail】
    • 组件【log4j2】
    • 组件【mqtt】
    • 组件【mybatis-plus】
    • 组件【nacos】
    • 组件【netty】
    • 组件【openapi-doc】
    • 组件【oss】
    • 组件【prometheus】
    • 组件【rate-limiter】
    • 组件【reactor】
    • 组件【redis】
    • 组件【secret】
    • 组件【security】
    • 组件【sensitive】
    • 组件【sms】
    • 组件【snail-job】
    • 组件【storage】
    • 组件【tdengine】
    • 组件【tenant】
    • 组件【test】
    • 组件【trace】
    • 组件【xss】
  • 环境搭建

    • Centos7安装Mysql 8.0.33
    • Centos7安装Redis 7.0.11
    • Centos7安装RocketMQ 5.1.1
    • Centos7安装Jdk 17.0.7
    • Centos7安装Docker 23.0.6
    • Centos7安装Elasticsearch 8.6.2
    • Docker安装RabbitMQ 3.12.2
    • Docker安装Postgresql 16.1
    • Ubuntu20.04安装Docker
    • Ubuntu20.04忘记密码或指纹错误
  • 常用命令

    • Centos7常用命令
    • Centos7常用命令
  • 快速上手

    • 项目启动【dev环境】
    • 项目启动【test环境】
    • 项目启动【prod环境】
    • 更新日志
  • 前端指南

    • 前端启动
  • 后端指南

    • COLA代码规范
    • SSL证书
    • 一键修改项目模块
    • 一键生成项目骨架
    • 一键修改项目版本号
    • 一键跳过测试用例
    • 一键生成后端COLA代码
    • 分布式链路跟踪之ELK日志
    • 一键检查代码规范
    • 动态路由
  • 项目部署

    • 项目部署之镜像打包与推送
  • 其他

    • Java如何快速转Go
    • Go快速开发API
    • Vue快速开发Api
    • React快速开发Api
  • 文章

    • 物联网之对接MQTT最佳实践
    • 物联网之使用Vertx实现MQTT-Server最佳实践【响应式】
    • vue3+lime-echart各种图表使用【懒人专用,建议收藏】
    • 物联网之使用Vertx实现TCP最佳实践【响应式】
    • 物联网之使用Vertx实现HTTPWebSocket最佳实践【响应式】
    • 物联网之使用Vertx实现UDP最佳实践【响应式】
    • Spring Cloud Gateway实现分布式限流和熔断降级
    • 物联网之常见网络配置
    • Go之封装Http请求和日志
    • 物联网之小白调试网关设备
    • 微服务之注册中心与ShardingSphere关于分库分表的那些事
  • 文章

    • IntelliJ IDEA插件推荐
  • 活动

    • KCloud-Platform-IoT 开源三周年快乐&父亲节快乐
  • 儒学

    • 儒学摘抄(一)
  • 禅语

    • 禅语摘抄(一)
  • 诗词

    • 诗词摘抄(一)
  • 道法

    • 道法摘抄(一)
  • 养生

    • 养生摘抄(一)
  • 读后感

    • 读《强者,都是含泪奔跑的人》读后感
  • 修行

    • 修身/养生/情感
  • 觉悟

    • 觉悟日记(一)
赞助
项目课程 (opens new window)
GitHub (opens new window)
首页
  • 开发手册

    • 组件【ai】
    • 组件【algorithm】
    • 组件【banner】
    • 组件【core】
    • 组件【bom】
    • 组件【cors】
    • 组件【domain】
    • 组件【crypto】
    • 组件【data-cache】
    • 组件【elasticsearch】
    • 组件【excel】
    • 组件【i18n】
    • 组件【idempotent】
    • 组件【influxdb】
    • 组件【kafka】
    • 组件【log】
    • 组件【lock】
    • 组件【mail】
    • 组件【log4j2】
    • 组件【mqtt】
    • 组件【mybatis-plus】
    • 组件【nacos】
    • 组件【netty】
    • 组件【openapi-doc】
    • 组件【oss】
    • 组件【prometheus】
    • 组件【rate-limiter】
    • 组件【reactor】
    • 组件【redis】
    • 组件【secret】
    • 组件【security】
    • 组件【sensitive】
    • 组件【sms】
    • 组件【snail-job】
    • 组件【storage】
    • 组件【tdengine】
    • 组件【tenant】
    • 组件【test】
    • 组件【trace】
    • 组件【xss】
  • 环境搭建

    • Centos7安装Mysql 8.0.33
    • Centos7安装Redis 7.0.11
    • Centos7安装RocketMQ 5.1.1
    • Centos7安装Jdk 17.0.7
    • Centos7安装Docker 23.0.6
    • Centos7安装Elasticsearch 8.6.2
    • Docker安装RabbitMQ 3.12.2
    • Docker安装Postgresql 16.1
    • Ubuntu20.04安装Docker
    • Ubuntu20.04忘记密码或指纹错误
  • 常用命令

    • Centos7常用命令
    • Centos7常用命令
  • 快速上手

    • 项目启动【dev环境】
    • 项目启动【test环境】
    • 项目启动【prod环境】
    • 更新日志
  • 前端指南

    • 前端启动
  • 后端指南

    • COLA代码规范
    • SSL证书
    • 一键修改项目模块
    • 一键生成项目骨架
    • 一键修改项目版本号
    • 一键跳过测试用例
    • 一键生成后端COLA代码
    • 分布式链路跟踪之ELK日志
    • 一键检查代码规范
    • 动态路由
  • 项目部署

    • 项目部署之镜像打包与推送
  • 其他

    • Java如何快速转Go
    • Go快速开发API
    • Vue快速开发Api
    • React快速开发Api
  • 文章

    • 物联网之对接MQTT最佳实践
    • 物联网之使用Vertx实现MQTT-Server最佳实践【响应式】
    • vue3+lime-echart各种图表使用【懒人专用,建议收藏】
    • 物联网之使用Vertx实现TCP最佳实践【响应式】
    • 物联网之使用Vertx实现HTTPWebSocket最佳实践【响应式】
    • 物联网之使用Vertx实现UDP最佳实践【响应式】
    • Spring Cloud Gateway实现分布式限流和熔断降级
    • 物联网之常见网络配置
    • Go之封装Http请求和日志
    • 物联网之小白调试网关设备
    • 微服务之注册中心与ShardingSphere关于分库分表的那些事
  • 文章

    • IntelliJ IDEA插件推荐
  • 活动

    • KCloud-Platform-IoT 开源三周年快乐&父亲节快乐
  • 儒学

    • 儒学摘抄(一)
  • 禅语

    • 禅语摘抄(一)
  • 诗词

    • 诗词摘抄(一)
  • 道法

    • 道法摘抄(一)
  • 养生

    • 养生摘抄(一)
  • 读后感

    • 读《强者,都是含泪奔跑的人》读后感
  • 修行

    • 修身/养生/情感
  • 觉悟

    • 觉悟日记(一)
赞助
项目课程 (opens new window)
GitHub (opens new window)
  • 开发手册

    • 组件【ai】
    • 组件【algorithm】
    • 组件【banner】
    • 组件【core】
    • 组件【bom】
    • 组件【cors】
    • 组件【domain】
    • 组件【crypto】
    • 组件【data-cache】
    • 组件【elasticsearch】
    • 组件【excel】
    • 组件【i18n】
    • 组件【idempotent】
    • 组件【influxdb】
    • 组件【kafka】
    • 组件【log】
    • 组件【lock】
    • 组件【mail】
    • 组件【log4j2】
    • 组件【mqtt】
    • 组件【mybatis-plus】
    • 组件【nacos】
    • 组件【netty】
    • 组件【openapi-doc】
    • 组件【oss】
    • 组件【prometheus】
    • 组件【rate-limiter】
    • 组件【reactor】
    • 组件【redis】
    • 组件【secret】
    • 组件【security】
    • 组件【sensitive】
    • 组件【sms】
    • 组件【snail-job】
    • 组件【storage】
    • 组件【tdengine】
    • 组件【tenant】
    • 组件【test】
    • 组件【trace】
    • 组件【xss】
  • 环境搭建

    • Centos7安装Mysql 8.0.33
    • Centos7安装Redis 7.0.11
    • Centos7安装RocketMQ 5.1.1
    • Centos7安装Jdk 17.0.7
    • Centos7安装Docker 23.0.6
    • Docker安装RabbitMQ 3.12.2
    • Centos7安装Elasticsearch 8.6.2
    • Docker安装Postgresql 16.1
    • Ubuntu20.04安装Docker
    • Ubuntu20.04忘记密码或指纹错误
  • 常用命令

    • Centos7常用命令
    • Docker常用命令
  • 快速上手

    • 项目启动【dev环境】
    • 项目启动【test环境】
    • 项目启动【prod环境】
    • 更新日志
  • 前端指南

    • 前端启动
  • 后端指南

    • COLA代码规范
    • SSL证书
    • 一键修改项目模块
    • 一键生成项目骨架
    • 一键修改项目版本号
    • 一键跳过测试用例
    • 一键生成后端COLA代码
    • 分布式链路跟踪之ELK日志
    • 一键检查代码规范
    • 动态路由
    • OAuth2.1流程
  • 项目部署

    • 项目部署之镜像打包与推送
  • 其他

    • Java如何快速转Go
    • Go快速开发API
    • Vue快速开发Api
    • React快速开发Api
  • 文章

    • 物联网之对接MQTT最佳实践
    • 物联网之使用Vertx实现MQTT-Server最佳实践【响应式】
    • vue3+lime-echart各种图表使用【懒人专用,建议收藏】
    • 物联网之使用Vertx实现TCP最佳实践【响应式】
    • 物联网之使用Vertx实现HTTPWebSocket最佳实践【响应式】
    • 物联网之使用Vertx实现UDP最佳实践【响应式】
    • Spring Cloud Gateway实现分布式限流和熔断降级
    • 物联网之常见网络配置
    • Go之封装Http请求和日志
      • 物联网之小白调试网关设备
      • 微服务之注册中心与ShardingSphere关于分库分表的那些事
    • 推荐

      • IntelliJ IDEA插件推荐
    • 活动

      • KCloud-Platform-IoT 开源三周年快乐&父亲节快乐
    • 指南
    • 文章
    KCloud-Platform-IoT
    2025-08-12
    目录

    Go之封装Http请求和日志

    你好呀,我的老朋友!我是老寇,欢迎来到老寇云平台!

    跟我一起学习封装Http请求和日志

    # Http请求

    封装Http请求,直接使用 net/http 就行,主要是有两点需要注意,Https如何关闭校验和客户端上传文件

    Https如何关闭校验

    // 跳过TLS证书校验
    client := &http.Client{
        Transport: &http.Transport{
           TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
        },
    }
    

    客户端上传文件

    上传文件需遵循 RFC 1867 (opens new window) 标准,因此,请求头 Content-Type设为 multipart/form-data;boundary=xxx

    http.go

    import (
        "bytes"
        "crypto/tls"
        "errors"
        "io"
        "mime/multipart"
        "net/http"
    )
    
    func SendRequest(method, url string, param io.Reader, header map[string]string) (*http.Response, error) {
        request, err := http.NewRequest(method, url, param)
        if err != nil {
           return nil, errors.New("创建 Request 失败,错误信息:" + err.Error())
        }
        if header != nil {
           for k, v := range header {
              request.Header.Set(k, v)
           }
        }
        return sendHttpRequest(request)
    }
    
    func GetFormFile(fileName string, buf []byte) (io.Reader, string, error) {
        body := &bytes.Buffer{}
        writer := multipart.NewWriter(body)
        part, err := writer.CreateFormFile("file", fileName)
        if err != nil {
           return nil, "", errors.New("创建 FormFile 失败,错误信息:" + err.Error())
        }
        _, err = io.Copy(part, bytes.NewReader(buf))
        if err != nil {
           return nil, "", errors.New("复制字节数组失败,错误信息:" + err.Error())
        }
        err = writer.Close()
        if err != nil {
           return nil, "", errors.New("关闭 Writer 失败,错误信息:" + err.Error())
        }
        return body, writer.FormDataContentType(), nil
    }
    
    func SendRequestAndGetBody(method, url string, param io.Reader, header map[string]string) ([]byte, error) {
        response, err := SendRequest(method, url, param, header)
        if err != nil {
           return nil, err
        }
        body, err := io.ReadAll(response.Body)
        if err != nil {
           return nil, errors.New("读取响应失败,错误信息:" + err.Error())
        }
        defer response.Body.Close()
        return body, nil
    }
    
    func sendHttpRequest(request *http.Request) (*http.Response, error) {
        client := &http.Client{
           Transport: &http.Transport{
              TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
           },
        }
        response, err := client.Do(request)
        if err != nil {
           return nil, errors.New("发送 HTTP 请求失败,错误信息:" + err.Error())
        }
        return response, nil
    }
    

    http_test.go

    func Test_Http(t *testing.T) {
       // Get请求
        header = map[string]string{
            "Cookie": 'token=123',
        }
        _, _ = SendRequest(http.MethodGet, "https://localhost/api/test", nil ,header)
    
       // Post请求
       _, _ = SendRequest(http.MethodPost, "https://localhost/api/test", strings.NewReader("username=a&password=123") ,header)
    
       // Post上传文件【表单】
       // 这里便于演示,随便定义一个字节数组
        buf := []byte('123')
        formFile, contentType, err := GetFormFile("image.jpg", buf)
        if err != nil {
           fmt.println(err.Error())
           return
        }
        header = map[string]string{
            "Content-Type": contentType,
        }
        // 上传文件
        _, _ = SendRequest(http.MethodPost, "https://localhost/api/upload", formFile, header)
    }
    

    # 日志

    日志对于一个项目来说是非常重要的,因此,很有必要根据业务进行挑选,go的常用日志包有glog、logrus和zap

    维度 glog (Google) logrus (社区维护) zap (Uber)
    项目背景 Kubernetes 等基础设施项目常用,轻量级 早期 Go 社区主流,已停止更新(仅维护) 高性能工业级实践,活跃维护
    性能 中等(基于标准库优化) 较低(反射序列化,内存分配多) 极高(预分配内存、零反射,每秒百万级日志)
    日志级别 4 级(Info/Warning/Error/Fatal) 6 级(Trace/Debug/Info/Warn/Error/Fatal) 7 级(Debug/Info/Warn/Error/Dpanic/Panic/Fatal)
    结构化日志 ❌ 不支持(仅文本格式) ✅ 支持(WithFields 动态类型) ✅ 强类型(zap.String()),SugaredLogger 兼容非结构化
    API 风格 类似标准库(如 glog.Info("msg")) 链式调用(logrus.WithField().Info()) 显式类型(zap.Info("msg", zap.String("k","v")))
    日志轮转 ❌ 需手动实现或第三方库 ❌ 依赖插件(如 file-rotatelogs)2 ✅ 原生支持(集成 lumberjack)
    内存分配 较少 较多(反射+动态字段) 极少(预分配+非反射)
    动态调级 ❌ 不支持 ✅ 需手动实现2 ✅ 原生支持(AtomicLevel)
    学习成本 低(类似标准库) 低(类似 fmt) 中(结构化 API 稍复杂,SugaredLogger 简化)
    适用场景 轻量级工具、K8s 生态兼容 旧项目维护、插件依赖型应用 高并发服务、云原生、性能敏感场景

    考虑到网关设备,为了节约内存空间和极致的性能,我们采用zap封装,zap不支持日志滚动,所以,我们使用第三方组件 timberjack增强 (opens new window),支持日志滚动,日志保留天数,日志级别

    log.go

    import (
        "errors"
        "github.com/DeRuina/timberjack"
        "go.uber.org/zap"
        "go.uber.org/zap/zapcore"
        "log"
        "time"
    )
    
    const (
        PROD = "prod"
    )
    
    type LogConfig struct {
        // 日志级别
        Level string `yaml:"level"`
        // 环境
        Profile string `yaml:"profile"`
        // 日志格式
        Pattern string `yaml:"pattern"`
        // 日志文件路径
        FilePath string `yaml:"file-path"`
        // 日志最大容量【单位M】
        MaxSize int `yaml:"max-size"`
        // 日志最大数量
        MaxBackups int `yaml:"max-backups"`
        // 日志保留时间【单位天】
        MaxAge int `yaml:"max-age"`
        // 是否压缩
        Compress bool `yaml:"compress"`
        // 本地时间,默认值:false(使用UTC)
        LocalTime bool `yaml:"local-time"`
        // json格式
        JsonFormat bool `yaml:"json-format"`
        // 转换频率
        RotationInterval time.Duration `yaml:"rotation-interval"`
        // 转换时间【分钟】
        RotateAtMinutes []int `yaml:"rotate-at-minutes"`
        // 日志时间格式
        BackupTimeFormat string `yaml:"backup-time-format"`
    }
    
    func (c *LogConfig) InitLogger() (*zap.Logger, error) {
        timberjackLogger := &timberjack.Logger{
           Filename:         c.FilePath,
           MaxSize:          c.MaxSize,
           MaxBackups:       c.MaxBackups,
           MaxAge:           c.MaxAge,
           Compress:         c.Compress,
           LocalTime:        c.LocalTime,
           RotationInterval: c.RotationInterval,
           RotateAtMinutes:  c.RotateAtMinutes,
           BackupTimeFormat: c.BackupTimeFormat,
        }
        log.SetOutput(timberjackLogger)
        defer timberjackLogger.Close()
        writeSyncer := zapcore.AddSync(timberjackLogger)
        // 配置日志级别
        levelConfig := zap.NewAtomicLevel()
        level, err := zapcore.ParseLevel(c.Level)
        if err != nil {
           return nil, errors.New("日志级别不存在,请重新配置,错误信息:" + err.Error())
        }
        levelConfig.SetLevel(level)
        // 配置环境
        var encoderConfig zapcore.EncoderConfig
        switch c.Profile {
        case PROD:
           encoderConfig = zap.NewProductionEncoderConfig()
        default:
           encoderConfig = zap.NewDevelopmentEncoderConfig()
        }
        // 设置时间格式
        encoderConfig.EncodeTime = c.customTimeEncoder
        var encoder zapcore.Encoder
        // Json格式
        if c.JsonFormat {
           encoder = zapcore.NewJSONEncoder(encoderConfig)
        } else {
           encoder = zapcore.NewConsoleEncoder(encoderConfig)
        }
        core := zapcore.NewCore(encoder, writeSyncer, levelConfig)
        return zap.New(core, zap.AddCaller()), nil
    }
    
    func (c *LogConfig) customTimeEncoder(t time.Time, enc zapcore.PrimitiveArrayEncoder) {
        enc.AppendString(t.Format(c.Pattern))
    }
    

    application.yaml

    log:
      # 级别
      level: error
      # 环境
      profile: prod
      # 日志格式
      pattern: 2006-01-02 15:04:05.000
      # 日志文件路径
      file-path: test.log
      # 日志最大容量【单位M】
      max-size: 500
      # 日志最大数量
      max-backups: 10
      # 日志保留时间【单位天】
      max-age: 30
      # 是否压缩
      compress: true
      # 本地时间,默认值:false(使用UTC)
      local-time: true
      # json格式,true为json格式日志
      json-format: false
      # 转换频率
      rotation-interval: 24h
      # 转换时间【分钟】
      rotate-at-minutes:
        - 0
        - 15
        - 30
        - 45
      # 日志时间格式
      backup-time-format: 2006-01-02-15-04-05
    

    config.go

    import (
        "errors"
        "gopkg.in/yaml.v3"
        "os"
    )
    
    type SystemConfig struct {
        Log LogConfig `yaml:"log"`
    }
    
    func GetSystemConfig(path string) (*SystemConfig, error) {
        data, err := os.ReadFile(path)
        if err != nil {
           return nil, errors.New("读取配置文件失败,错误信息:" + err.Error())
        }
        sysConfig := &SystemConfig{}
        err = yaml.Unmarshal(data, sysConfig)
        if err != nil {
           return nil, errors.New("配置文件反序列化失败,错误信息:" + err.Error())
        }
        return sysConfig, nil
    }
    

    log_test.go

    import (
        "testing"
    )
    
    func Test_Log(t *testing.T) {
        config, err := GetSystemConfig("application.yaml")
        if err != nil {
           t.Error(err.Error())
           return
        }
        logger, err := config.Log.InitLogger()
        if err != nil {
           t.Error(err.Error())
           return
        }
        logger.Info("信息")
        logger.Warn("警告")
        logger.Error("错误")
        t.Log("日志测试通过")
    }
    

    注意:部署到网关上面,日志无法打印,需要对日志增加权限和不能以sudo运行

    # 增加日志权限
    sudo chmod -R 7777 /home/a/app/logs
    # 运行项目,不能以sudo运行项目,否则日志无法打印,这是我遇到的坑
    nohup /home/a/app/log > /dev/null 2>&1 &
    

    我是老寇,我们下次再见啦!

    上次更新: 8/17/2025, 1:11:40 PM
    物联网之常见网络配置
    物联网之小白调试网关设备

    ← 物联网之常见网络配置 物联网之小白调试网关设备→

    Theme by Vdoing | Copyright © 2022-2025 laokou | Apache 2.0 License
    • 跟随系统
    • 浅色模式
    • 深色模式
    • 阅读模式