前言

先说一下为什么要搞这个小东西?

米攸服务端前期主要是基于 Go 构建的,版本迭代过程中,业务复杂度不断增加,再加上中员团队有人员变动,考虑到目前团队的技术背景,我们开始考虑把接口服务分批迁移到 Java,开发效率和可控程度更高一些。其中有一些接口服务涉及周边模块较多,迁移的时间成本较高,我们决定暂时继续维护这些接口。后续接口需要升级时,如果变动较小,我们直接修改 Go 代码;如果变动较大,我们在 Go 代码中使用 HTTP 的方式调用 Java 接口实现,相当于给原有接口加了一个 钩子。为了减化接口调用代码编写的复杂度,我们考虑在 Go 代码中内置两个工具函数:GetPost,方便调用 Java 接口。

本文重点讨论 Get 和 Post 函数实现的关键细节,并给出核心代码。

Result

Java 接口的返回结果是一个 固定格式Json 字符串:

  • id

    请求ID,字符串。

  • code

    状态码,整数。

  • msg

    状态信息,字符串。

  • data

    数据,任意类型。

我们使用 结构体 封装返回结果:

  type Result struct {Id   string      `json:"id"`Code int         `json:"code"`Msg  string      `json:"msg"`Data interface{} `json:"data"`}

可以发现,结构体的字段名称和返回结果的字段名称是不一样的(首字母大小写),两者相互转换的时候名称会对应不上,需要在结构体中使用类似 `json:“id”` 的声明,把结构体中的字段名称和返回结果的字段名称一一对应起来。

特别注意:声明字段名称时标点符号的使用。

Client

Go 提供的 Http 客户端(Client)实例是线程安全的,一个进程内只需要有一个即可:

  var client = http.Client{}

Get

Get 函数的参数应该有两个:接口路径(url)和 接口参数(params)。接口路径比较简单,就是一个字符串(string),我们主要讨论接口参数。

我们使用 Query String 的方式传递 Get 参数,如:/interface/param1=value1&param2=value2,接口参数的类型应该是一个内部包含多个键值对的 字典(map[string]interface{}),键名称是参数名称,键值是参数值;考虑到实际使用场景,参数值的类型限制为三种:

  • string
  • int
  • float64

因为参数的值类型是不确定的,所以使用 interface{} 表示任意类型,函数内部判断具体类型。

因为调用接口时需要添加 请求头请求参数,所以不能直接使用 http.Get 这样的简化函数,实现流程:

创建请求

使用 http.NewRequest 创建请求:

  req, err := http.NewRequest("GET", url, nil)

添加请求头

设置请求响应的内容类型为 json:

  req.Header.Add("Content-Type", "application/json")

设置调用接口时的 Token:

  req.Header.Add("token", MEETU_API_TOKEN)

添加请求参数

创建请求参数:

  query := req.URL.Query()

逐个添加请求参数:

 query.Add(name, value)

注意:添加请求参数时,name(参数名称) 和 value(参数类型) 类型都是字符串。

如前文所述,接口参数是一个字典类型的变量,我们需要遍历这个变量中的每一个键值对,逐个添加参数。遍历可以使用 Range:

  for name, value := range params {...}

如前文所述,参数值类型是有限制的,遍历过程中,我们需要判断参数值类型是否符合要求。类型判断可以使用 value.(type):

  switch value.(type) {case string:query.Add(name, value.(string))case int:query.Add(name, strconv.Itoa(value.(int)))case float64:query.Add(name, strconv.FormatFloat(value.(float64), 'f', -1, 64))default:return Result{}, errors.New("params type only support string, int and float64")}

使用 value.(string)、value.(int) 和 value.(float64) 把变量 value(类型:interface{}) 分别转换为类型 string、int 和 float64 的变量。使用 strconv.Itoa 把 int 变量转换为 string 变量,使用 strconv.FormatFloat 把 float64 变量转换为 string 变量。

请求参数值可能包含特殊字符,需要转义:

  req.URL.RawQuery = query.Encode()

请求参数添加完成。

执行请求,获取结果

  resp, err := client.Do(req)defer resp.Body.Close()

defer 表示 Get 函数执行完成之后,关闭 Http 客户端内部的网络连接。

解析结果

响应体(resp.Body)的数据是字节流,需要解码并反序列化成类型为 Result 的变量 result:

  json.NewDecoder(resp.Body).Decode(&result)

返回结果

  return result, nil

到此,Get 函数实现完成,代码如下:

  func Get(url string, params map[string]interface{}) (Result, error) {req, err := http.NewRequest("GET", url, nil)if err != nil {return Result{}, err}req.Header.Add("Content-Type", "application/json")req.Header.Add("token", MEETU_API_TOKEN)if params != nil {query := req.URL.Query()for name, value := range params {switch value.(type) {case string:query.Add(name, value.(string))case int:query.Add(name, strconv.Itoa(value.(int)))case float64:query.Add(name, strconv.FormatFloat(value.(float64), 'f', -1, 64))default:return Result{}, errors.New("params type only support string, int and float64")}}req.URL.RawQuery = query.Encode()}resp, err := client.Do(req)if err != nil {return Result{}, err}defer resp.Body.Close()var result Resulterr = json.NewDecoder(resp.Body).Decode(&result)if err != nil {return Result{}, err}return result, nil}

Post

Post 函数的实现过程整体和 Get 是类似的,唯一不同的就是请求参数的处理。我们使用 Body 传递 Post 参数。

其余内容请参考:Go Http Get 和 Post 工具函数。

Go Http Get 和 Post 工具函数相关推荐

  1. 关于Vue中常用的工具函数封装

    ## Vue 项目中工具函数,我们通常会添加到Vue的原型中,这样就实现了全局函数 import Vue from 'vue' Vue.prototype.$tools = function (){} ...

  2. setwindowshookex回调函数不执行_不一样的“悬停几秒后执行函数”?一个开源工具函数,请注意查收...

    大家好,我是 vortesnail. 前言: 最近这几个星期,一直都在维护自己的基于 React 的开源播放器组件,以为功能基本都差不多了,却忽视了播放器一个很重要的功能:鼠标悬停在视频播放界面时,在 ...

  3. 从零开始学习jQuery (九) jQuery工具函数

    本系列文章导航 从零开始学习jQuery (一) 开天辟地入门篇 从零开始学习jQuery (二) 万能的选择器 从零开始学习jQuery (三) 管理jQuery包装集 从零开始学习jQuery ( ...

  4. PHP中文处理工具函数的用法总结

    --- PHP中文处理工具函数之空格 --- string GBspace(string) --------- 每个中文字之间加空格 string GBunspace(string) ------- ...

  5. 原生JS基于window.scrollTo()封装垂直滚动动画工具函数

    概要: 原生JS基于window.scrollTo()封装垂直滚动动画工具函数,可应用与锚点定位.回到顶部等操作. ####封装原因: 在vue项目中,遇到需要实现垂直滚动效果的需求,初步想到的方法有 ...

  6. 用来枚举属性的对象工具函数

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  7. 单步调试学习NgRx createSelector 工具函数的使用方式

    createSelector实现代码里,前面n - 1 个参数都是selector,只有最后一个是projection函数: 将输入参数里包含的selector和projector依次提取出来: 将传 ...

  8. axios源码中的10多个工具函数,值得一学~

    大家好,我是若川.最近组织了源码共读活动,感兴趣的可以点此加我微信 ruochuan12 参与,每周大家一起学习200行左右的源码,共同进步.同时极力推荐订阅我写的<学习源码整体架构系列> ...

  9. 初学者也能看懂的 Vue2 源码中那些实用的基础工具函数

    1. 前言 大家好,我是若川.最近组织了源码共读活动,感兴趣的可以加我微信 ruochuan12 想学源码,极力推荐之前我写的<学习源码整体架构系列>jQuery.underscore.l ...

  10. 学习尤雨溪写的 Vue3 源码中的简单工具函数

    大家好,我是若川.最近组织了源码共读活动.每周读 200 行左右的源码.很多第一次读源码的小伙伴都感觉很有收获,感兴趣可以加我微信ruochuan12,拉你进群学习. 初学者也能看懂的 Vue3 源码 ...

最新文章

  1. @程序员:Python 3.8正式发布,重要新功能都在这里
  2. Ubutu16.04+Cuda9.2/9.0+Cudnn7.12/7.05+TensorFlow-gpu-1.8/1.6
  3. DWZ 验证 CLASS 规则
  4. SQL语法之基础查询(进阶1)and条件查询(进阶2)
  5. 系统无ifconfig,一条命令获取本机ip并将其赋值给指定变量来使用
  6. 驱动之LCD的介绍与应用20170209
  7. 【...】小程序扩展运算符 ... 说明
  8. 蓝牙小电池图标_提高MacBook电池寿命的15个技巧
  9. ajax请求l类型,jquery 的ajax请求示例和注意事项
  10. (转)关于数据库存储过程分页DatagridView BindingNavigator 控件的详细实现
  11. Android设计模式(十五)--备忘录模式
  12. 面向对象设计——七大原则
  13. matlab实现3维测井曲线绘制
  14. SQL基础教程读书笔记
  15. QT学习:制作树形列表菜单
  16. 医院计算机网络信息安全与管理,医院信息安全管理制度网络版(全文完整版)...
  17. UltraISO软碟通安装与刻盘以及安装镜像
  18. 电子制作:红外遥控器检测仪的制作
  19. chapter4.面对对象
  20. 【gloomyfish】数据分析之 – 离群值(Outliers) BoxPlot

热门文章

  1. GPS基础知识(二)、 GPS时间
  2. 关于torch.size()和torch.size(0)
  3. 代码签名、驱动签名的常见问题解答
  4. 手机版专题页面的注意事项
  5. Aid Learning0.87F3安装Home Assistant智能家居
  6. 关于 APP 电量测试步骤总结
  7. C/C++ 谈回调函数
  8. HiveQL 书写规范
  9. 答复: 比丰田生产方式和精益的消除浪费,更重要的东西
  10. 流媒体技术知识梳理整合