前言

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

米攸服务端前期主要是基于 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 Result err = 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. JQuery中的工具函数总结

    前提引入 前提当然也是要引入Jquery啦... <script src="http://libs.baidu.com/jquery/1.9.0/jquery.js" typ ...

  2. 五、jquery使用工具函数

    工具函数对应的网址在 http://api.jquery.com/categouy/utilities/   工具函数处理对象的不同,可以将其分为几大类别:浏览器的检测.数组和对象的操作.字符串的操作 ...

  3. jQuery工具函数(转)

    原文地址:http://www.cnblogs.com/kissdodog/archive/2012/12/27/2835561.html 作者:逆心 ------------------------ ...

  4. jQuery实用工具函数

    1. 什么是工具函数 在jQuery中,工具函数是指直接依附于jQuery对象.针对jquery对象本身定义的说法,即全局性的函数,我们统称为工具函数,或Utilities函数.它们有一个明显的特征, ...

  5. javascript工具函数

    第一部分 JavaScript工具函数 转义特殊字符为html实体   HtmlEncode: function(str){ return str.replace(/&/g, '&') ...

  6. 读<jQuery 权威指南>[6]--实用工具函数

    官方地址:http://api.jquery.com/category/utilities/ 一.数组和对象操作 1. $.each——遍历 $.each(obj,function(param1,pa ...

  7. AJAX编程-封装ajax工具函数

    即 Asynchronous [e'sɪŋkrənəs] Javascript And XML,AJAX 不是一门的新的语言,而是对现有技术的综合利用.本质是在HTTP协议的基础上以异步的方式与服务器 ...

  8. JQ工具函数

    在jQuery中,工具函数是指直接依附于jQuery对象,针对jQuery对象本身定义的方法,即全局性的,我们统称为工具函数,或Utilites函数 主要作用于:字符串.数组.对象 API:工具函数 ...

  9. jquery源码分析-工具函数

    jQuery的版本一路狂飙啊,现在都到了2.0.X版本了.有空的时候,看看jquery的源码,学习一下别人的编程思路还是不错的. 下面这里是一些jquery的工具函数代码,大家可以看看,实现思路还是很 ...

  10. jQuery工具函数

    要点:1.字符串操作2.数组和对象操作3.测试操作4.URL 操作5.浏览器检测6.其他操作 工具函数是指直接依附于 jQuery 对象,针对 jQuery 对象本身定义的方法,即全局性的函数.它的作 ...

随机推荐

  1. tcp粘包问题原因及解决办法

    1.粘包概念及产生原因 1.1粘包概念: TCP粘包是指发送方发送的若干包数据到接收方接收时粘成一包,从接收缓冲区看,后一包数据的头紧接着前一包数据的尾. 粘包可能由发送方造成,也可能由接收方造成. ...

  2. 学习Keepalived(三)

    1.1Keepalived高可用软件 Keepalived起初是专为LVS设计的,专门用来监控LVS集群系统中各个服务节点的状态,后来又加入了VRRP的功能,因此除了配合LVS服务外,也可以作为其他服 ...

  3. 学习openstack(六)

    VIII openstack(1) 传统的数据中心面临的问题:成本.效率(要快).管理方面(物理机.云主机): 云计算:对运维需求总体量是减少了,尤其是硬件工程师,对运维的技术要求提高了: 云计算是个 ...

  4. ACM - 动态规划 - UVA 1347 Tour

    UVA 1347 Tour 题解 题目大意:有 \(n\) 个点,给出点的 \(x\).\(y\) 坐标.找出一条经过所有点一次的回路,从最左边的点出发,严格向右走,到达最右点再严格向左,回到最左点. ...

  5. Citus 分布式 PostgreSQL 集群 - SQL Reference(手动查询传播)

    手动查询传播 当用户发出查询时,Citus coordinator 将其划分为更小的查询片段,其中每个查询片段可以在工作分片上独立运行.这允许 Citus 将每个查询分布在集群中. 但是,将查询划分为 ...

  6. 关于css布局、居中的问题以及一些小技巧

    CSS的两种经典布局 左右布局 一栏定宽,一栏自适应 <!-- html --> <div class="left">定宽</div> < ...

  7. 用jq实现移动端滑动轮播以及定时轮播效果

    Html的代码: <div class="carousel_img"> <div class="car_img" style="ba ...

  8. java中请给出例子程序:找出n到m之间的质数。

    9.1 找出100到200之间的质数.  public class Test {     public static void main(String[] args){         for (in ...

  9. Photoshop之用“色彩范围”命令抠像

    1. 打开一个文件.执行"选择>色彩范围",勾选"本地化颜色族",然后在任务背景上单击取样. 2. 取好样以后点击确定,图片如下所示,执行"选择 ...

  10. 底部footer挡住上面内容的bug

    当设置底部footer的样式为: .footer{ position: fixed; height: 49px; bottom: 0; background: #fff; } 这样会挡住上面的内容,修 ...