go json 实践中遇到的坑

在使用 go 语言开发过程中,经常需要使用到 json 包来进行 json 和 struct 的互相转换,在使用过程中,遇到了一些需要额外注意的地方,记录如下。 整数变浮点数问题 假设有一个 Person 结构,其中包含 Age int64 和 Weight float64 两个字段,现在通过 json 包将 Person 结构转为 map[string]interface{},代码如下。 type Person struct { Name string Age int64 Weight float64 } func main() { person := Person{ Name: "Wang Wu", Age: 30, Weight: 150.07, } jsonBytes, _ := json.Marshal(person) fmt.Println(string(jsonBytes)) var personFromJSON interface{} json.Unmarshal(jsonBytes, &personFromJSON) r := personFromJSON.(map[string]interface{}) } 代码执行到这里看上去一切正常,但是打印一下 map[string]interface{} 就会发现不太对了。 fmt.Println(reflect.TypeOf(r["Age"]).Name()) // float64 fmt.Println(reflect.TypeOf(r["Weight"]).Name()) // float64 转换成 map[string]interface{} 之后,原先的 uint64 和 float64 类型都被转换成了 float64 类型,这显然是不符合我们的预期的。 ...

十二月 24, 2018 · 2 分钟 · Zhiya

基于 JWT + Refresh Token 的用户认证实践

HTTP 是一个无状态的协议,一次请求结束后,下次在发送服务器就不知道这个请求是谁发来的了(同一个 IP 不代表同一个用户),在 Web 应用中,用户的认证和鉴权是非常重要的一环,实践中有多种可用方案,并且各有千秋。 基于 Session 的会话管理 在 Web 应用发展的初期,大部分采用基于 Session 的会话管理方式,逻辑如下。 客户端使用用户名密码进行认证 服务端生成并存储 Session,将 SessionID 通过 Cookie 返回给客户端 客户端访问需要认证的接口时在 Cookie 中携带 SessionID 服务端通过 SessionID 查找 Session 并进行鉴权,返回给客户端需要的数据 基于 Session 的方式存在多种问题。 服务端需要存储 Session,并且由于 Session 需要经常快速查找,通常存储在内存或内存数据库中,同时在线用户较多时需要占用大量的服务器资源。 当需要扩展时,创建 Session 的服务器可能不是验证 Session 的服务器,所以还需要将所有 Session 单独存储并共享。 由于客户端使用 Cookie 存储 SessionID,在跨域场景下需要进行兼容性处理,同时这种方式也难以防范 CSRF 攻击。 基于 Token 的会话管理 鉴于基于 Session 的会话管理方式存在上述多个缺点,无状态的基于 Token 的会话管理方式诞生了,所谓无状态,就是服务端不再存储信息,甚至是不再存储 Session,逻辑如下。 客户端使用用户名密码进行认证 服务端验证用户名密码,通过后生成 Token 返回给客户端 客户端保存 Token,访问需要认证的接口时在 URL 参数或 HTTP Header 中加入 Token 服务端通过解码 Token 进行鉴权,返回给客户端需要的数据 ...

十二月 13, 2018 · 2 分钟 · Zhiya

通过 ngrok 实现 ssh 内网穿透

ngrok 用 ssh 访问一台主机,如果和主机在一个局域网中或者主机拥有公网 IP,就可以使用 ssh 命令直接连接主机的 IP 地址,但是大部分公司和家庭内部都是局域网,并不能给局域网内的每一台主机都分配一个公网 IP,这时候就需要进行内网穿透,才能从外部连接到局域网内的主机。 ngrok 是一个反向代理工具,可以实现将内网的端口暴露到公网,通过 ngrok,也能将 ssh 使用的端口暴露出去,以此实现 ssh 的内网穿透。 注册并下载 ngrok 访问 https://ngrok.com/ 注册 ngrok 账号并下载 ngrok 客户端。 查看 ngrok 的 token 访问 https://dashboard.ngrok.com/auth 查看 token 并复制。 在内网机器上启动 ngrok 连接 ngrok 账号 ngrok authtoken 5TqUhMnum6ntDE8Z5HkNb_49F9ffzzcV9V7pKLVdDYc 启动 ngrok 并打开 22 端口转发 ngrok tcp 22 --log=stdout > "$HOME/ngrok.log" --region ap & 其中 region 的 ap 代表 ngrok 新加坡节点,访问速度相比美国节点会快一些。访问 https://ngrok.com/docs#config-options 可以查看支持的所有区域。 访问 http://127.0.0.1:4040。 可以看到一个 tcp 开头的地址,通过访问这个地址,就可以转发到本机的 22 端口上。 ...

十二月 10, 2018 · 1 分钟 · Zhiya

Unicode 和 UTF-8

Unicode 和 UTF-8 的概念是一个非常基础和重要,但是却容易被忽略的问题。 字符集 在计算机系统中,所有的数据都以二进制存储,所有的运算也以二进制表示,人类语言和符号也需要转化成二进制的形式,才能存储在计算机中,于是需要有一个从人类语言到二进制编码的映射表。这个映射表就叫做字符集。 ASCII 最早的字符集叫 American Standard Code for Information Interchange(美国信息交换标准代码),简称 ASCII,由 American National Standard Institute(美国国家标准协会)制定。在 ASCII 字符集中,字母 A 对应的字符编码是 65,转换成二进制是 0100 0001,由于二进制表示比较长,通常使用十六进制 41。 GB2312、GBK ASCII 字符集总共规定了 128 种字符规范,但是并没有涵盖西文字母之外的字符,当需要计算机显示存储中文的时候,就需要一种对中文进行编码的字符集,GB 2312 就是解决中文编码的字符集,由国家标准委员会发布。同时考虑到中文语境中往往也需要使用西文字母,GB 2312 也实现了对 ASCII 的向下兼容,原理是西文字母使用和 ASCII 中相同的代码,但是 GB 2312 只涵盖了 6000 多个汉字,还有很多没有包含在其中,所以又出现了 GBK 和 GB 18030,两种字符集都是在 GB 2312 的基础上进行了扩展。 Unicode 可以看到,光是简体中文,就先后出现了至少三种字符集,繁体中文方面也有 BIG5 等字符集,几乎每种语言都需要有一个自己的字符集,每个字符集使用了自己的编码规则,往往互不兼容。同一个字符在不同字符集下的字符代码不同,这使得跨语言交流的过程中双方必须要使用相同的字符编码才能不出现乱码的情况。为了解决传统字符编码的局限性,Unicode 诞生了,Unicoide 的全称是 Universal Multiple-Octet Coded Character Set(通用多八位字符集,简称 UCS)。Unicode 在一个字符集中包含了世界上所有文字和符号,统一编码,来终结不同编码产生乱码的问题。 字符编码 UTF-8 Unicode 统一了所有字符的编码,是一个 Character Set,也就是字符集,字符集只是给所有的字符一个唯一编号,但是却没有规定如何存储,一个编号为 65 的字符,只需要一个字节就可以存下,但是编号 40657 的字符需要两个字节的空间才可以装下,而更靠后的字符可能会需要三个甚至四个字节的空间。 ...

十二月 7, 2018 · 1 分钟 · Zhiya

理解Golang的Time结构

在 golang 中创建并打印一个时间对象,会看到如下输出 2018-10-26 14:15:50.306558969 +0800 CST m=+0.000401093 前面表示的意义好理解,分别是年月日和时间时区,最后的 m=+xxxx 这部分代表什么呢? Monotonic Clocks 和 Wall Clocks 根据 golang 的 time 包的文档可以知道,golang 的 time 结构中存储了两种时钟,一种是 Wall Clocks,一种是 Monotonic Clocks。 Wall Clocks,顾名思义,表示墙上挂的钟,在这里表示我们平时理解的时间,存储的形式是自 1970 年 1 月 1 日 0 时 0 分 0 秒以来的时间戳,当系统和授时服务器进行校准时间时间操作时,有可能造成这一秒是 2018-1-1 00:00:00,而下一秒变成了 2017-12-31 23:59:59 的情况。Monotonic Clocks,意思是单调时间的,所谓单调,就是只会不停的往前增长,不受校时操作的影响,这个时间是自进程启动以来的秒数。 如果每隔一秒生成一个 Time 并打印出来,就会看到如下输出。 2018-10-26 14:15:50.306558969 +0800 CST m=+0.000401093 2018-10-26 14:15:51.310559881 +0800 CST m=+1.004425285 2018-10-26 14:15:52.311822486 +0800 CST m=+2.005711106 2018-10-26 14:15:53.314599457 +0800 CST m=+3.008511329 2018-10-26 14:15:54.31882248 +0800 CST m=+4.012757636 2018-10-26 14:15:55.320059921 +0800 CST m=+5.014018292 2018-10-26 14:15:56.323814998 +0800 CST m=+6.017796644 2018-10-26 14:15:57.324858749 +0800 CST m=+7.018863606 2018-10-26 14:15:58.325164174 +0800 CST m=+8.019192224 2018-10-26 14:15:59.329058535 +0800 CST m=+9.023109863 2018-10-26 14:16:00.329591268 +0800 CST m=+10.023665796 可以看到 m=+后面所显示的数字,就是文档中所说的 Monotonic Clocks。 ...

十月 26, 2018 · 2 分钟 · Zhiya