使用Golang开发一个本地代理
引言
最近需要对接一个接口,人家提供了两种调用方式,第一种是基于IE浏览器的Active,第二种是动态链接库dll。我们公司的产品不支持IE,所以只能通过调用dll来完成了。
之前我已经用Java实现了这个代理,但是感觉很笨重,依赖于容器还有JVM一大堆,这个代理要安装在客户端电脑上,基于Http协议来调用,然后透传参数调用dll,将返回的结果转换为Json。
如今我想用Golang来实现这个功能,它不依赖特定的运行环境,而且天然高并发,适合做网络通信相关,结合了Java的高效和C的高性能。
一、功能拆解
- http模块
- 调用dll
- 返回结果处理
功能大致上分为三步,三步独立完成,分步进行。第一个很简单,网上一搜就出来了,也没遇到什么波折。然后直接测试调用dll,这个耽误了不少时间,不知道问题出在哪,又不好测试,打的包不在dll所在文件夹里,每次还要复制过去测试。
二、遇到的问题
1. 对于入参和出参的处理
void _stdcall PostAndRecvEx(IN char* pszPost, OUT char* pszRecv)
参数:
pszPost 输入XML信息
pszRecv 返回XML信息
返回值:无
2. 程序异常退出
由于dll文件在指定的安装目录,将golang生成的exe复制过去后才能找到它,但是一运行却出现闪退,根本不知道哪里出了问题。
3. 中文乱码
这里体现在两个地方,一是输入参数无法被dll中的函数识别,一直报错。第二个是输出的xml中包含中文乱码。
4. 返回结果无法映射到结构体
要转成Json,首先应该定义结构体,我是利用返回结果直接测试的,但是返回的xml无法映射到结构体对应的字段上,怀疑是编码问题,返回的xml指定了GBK(encoding="gbk")。由于是模拟的返回数据,我直接修改了编码发现可以映射到指定字段。网上查了下没什么好办法,看到这个很妙就直接用了:
xmlDataRsp = strings.Replace(xmlDataRsp, "gbk", "UTF-8", -1)
三、涉及知识点
1. 如何使用http模块写一个服务(找个官方的示例)
import (
"fmt"
"log"
"net/http"
)
func handler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hi there, I love %s!", r.URL.Path[1:])
}
func main() {
http.HandleFunc("/", handler)
log.Fatal(http.ListenAndServe(":8080", nil))
}
2. 如何调用dll(这个也有几种方式)
dll := syscall.NewLazyDLL("NISEC_SKSC.dll")
proc := dll.NewProc("PostAndRecvEx")
3. 捕获异常 明确问题点
defer func() {
//恢复程序的控制权
err := recover()
if err != nil {
fmt.Println(err)
}
}()
// 可能出问题的代码
4. 如何使用cgo
//#include <stdio.h>
//#include <stdlib.h>
import "C"
import (
"bytes"
"strconv"
"unsafe"
)
func main() {
cs := C.CString("你好")
defer C.free(unsafe.Pointer(cs))
println(cs)
}
一开始以为注释是没用的,后来才知道编译器识别加注释的c代码(通过import "C")
5. 底层数据类型不一致的处理
使用java调用dll的时候我特地在后面加了结束符:
JNAOperateDll.instanceDll.PostAndRecvEx((xmlStr + "\0") .getBytes("gbk"), b);
用golang的时候,我也一直不知道如何处理,到底该用字符串加"\0",还是字节加\x00。
这就要了解golang和c对字符的处理,c需要通过结束符来判断字符串何时结束,而golang不需要,它有长度标识。
6. xml转json
golang要转json,需要定义结构体来搭桥,所有属性都要有对应的字段。网上找到一个不需要结构体的,但是star数量不多,而且没下载下来。
四、总结
1. 做事情要知道事情的边界
像我们这个需求,要和其他接口交互,而且不是基于http协议,我们公司的产品放弃了IE的支持,所以只能通过调用dll来实现。这就是边界,无法突破的壁垒。
2. 在边界内力求做到最好
知道了事情的边界,力求在边界内做到最好。起初我就觉得用Java来实现不太好,但是客户催得紧,还要调试这些接口,就迅速用Java实现了。后来回过头我就想着如何优化它,如何一键启动甚至开机自启,如何设置成windows服务,但是这都改变不了它庞大且不利于传播的事实,后来想起来golang,这玩意真是天生做这个的料。
3. 遇到问题不要轻易放弃
在写这个代理的过程中,遇到了较多困难,毕竟是不熟悉的语言,虽然它的功能看起来很简单,但是我一开始还是有点虚,例如看到了指针,我就怕遇到了这些环环相扣的陷进去了,不过我还是鼓励自己不断去尝试,边做边学。
4. 形成自己做事的方法
在做这个工具的时候,我是分几步进行的,大方向上没有变,最后把代码合起来,就是一个完整的功能。我觉得这样拆分可以各个击破,专注于一个个点,而且可以将难度分化,给人以信心。
这次我也没有一开始就去看golang的语法,学习那些东西,我是直接开干,需要什么我就去查什么。当你学会一种开发语言后,需要借助于另一个语言完成某个功能,这种方法我觉得很好,不会陷入另一个语言的大坑,针对目标在实践中学习,高效而深刻。
使用Golang开发一个本地代理的更多相关文章
- golang开发一个简单的grpc
0.1.索引 https://waterflow.link/articles/1665674508275 1.什么是grpc 在 gRPC 中,客户端应用程序可以直接调用不同机器上的服务器应用程序上的 ...
- 用Java开发一个本地服务管理软件
一.最终界面先贴上最终效果图,图1为初始化界面,图二为点击启动/停止之后的中间过渡状态,图三为启动成功后弹出的提示框 把动态gif图片嵌入到jpg背景图中?用Adobe ImageReady即可办到 ...
- 3 微信开发本地代理环境的搭建--实现将内网ip映射到外网
微信公众号的开发,要搭建网站,并且随时都有可能修改网站内容进行调试,这就需要临时外网能返回本地开发环境搭建的项目进行测试,即内网映射到公网,但是好多开发者没有自己的域名和服务器,这里我们先来搭建一个本 ...
- vue-webpack项目本地开发环境设置代理解决跨域问题
前言: 一般跨域问题只要后端配置好的话,是不需要前端做处理的,但也不能保证你遇到的所有后端都能很好的处理这个问题,这个时候可能就需要前端设置代理解决这个问题了. 配置方法: 1. config/ind ...
- mark一篇文章--用nodejs搭建一个本地反向代理环境
调试线上代码的时候,我们经常遇到的一个问题就是 本地一套环境,线上一套环境,本地没有的文件用线上的这种需求.我简单来说下使用nodejs如何做到. 先说下不用nodejs我们怎么做,工具比如fiddl ...
- 十分钟学会Golang开发gRPC服务
gRPC是Google发起的一个开源RPC框架,使用HTTP/2传输协议,使用Protocol Buffers编码协议,相比RESTful框架的程序性能提高不少,而且当前流行的编程语言基本都已经支持. ...
- 使用 docker-compose 部署 golang 的 Athens 私有代理
go中私有代理搭建 前言 为什么选择 athens 使用 docker-compose 部署 配置私有仓库的认证信息 配置下载模式 部署 使用秘钥的方式认证私有仓库 1.配置秘钥 2.配置 HTTP ...
- 从零开始开发一个简易的类vue-cli构建工具
代码地址:https://github.com/cheer4chai/webpack-learning 仿照vue-cli开发这个工具的目的是了解webpack的基本设置,以及vue-cli的工作原理 ...
- Linux下golang开发环境搭建
对于golang开发来说,Windows下可以用vscode或者liteide都不错,但是Linux下的开发也就只有vim了,所以怎么搞笑的利用vim进行golang开发呢? 参考官方推荐的一个插件: ...
随机推荐
- 缓存面板获取之前页面选中的数据Objuid的方法
String partUid = request.getParameter("contextInstanceUid"); contextInstanceUid是存在总线总的键名,存 ...
- 《剑指offer》— JavaScript(26)二叉搜索树与双向链表
二叉搜索树与双向链表 题目描述 输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表.要求不能创建任何新的结点,只能调整树中结点指针的指向. 思路 递归思想:把大问题转换为若干小问题: 由于Ja ...
- 简单的sql分组统计
一个记录员工打卡时间的表,只有两个有效字段 员工名称,打卡时间,现在要统计某一天中,每个员工的打卡次数.最早打卡时间.最晚打卡时间,问sql怎么写? 其实这个sql很简单, 1.首先要明确既然是按每个 ...
- Go 语言编程规范
1. gofmt 命令 大部分的格式问题可以通过 gofmt 来解决,gofmt 自动格式化代码,保证所有的 go 代码与官方推荐的格式保持一致,所有格式有关问题,都以gofmt的结果为准.所以,建议 ...
- Java URL
1.在网络编程的时候,一定不要忘记 <uses-permission android:name="android.permission.INTERNET"></u ...
- gcc初步窥探
由于没有上过Linux编程这门课,所以Linux学得很水啊!!用来用去都是ls -al ; cd .. ;这些渣命令,尤其gcc都不知道什么东西来的,所以先学一下吧. 一.程序的编译过程 对于GUN编 ...
- HDU 4509 湫湫系列故事——减肥记II (简单模拟)
题意:一天一共有1440分钟,主人公每天有n件事要做,给出这n件事开始跟结束的时间,然后让你求出,空闲的时间的总分钟数是多少. 解题报告:简单模拟,只要开个一维数组标记那个每个分钟是否是有事的就可以了 ...
- c++刷题(43/100)矩阵旋转打印
题目1:矩阵旋转打印 输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下4 X 4矩阵: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 则 ...
- python enumerate用法总结【转】
enumerate()说明 enumerate()是python的内置函数 enumerate在字典上是枚举.列举的意思 对于一个可迭代的(iterable)/可遍历的对象(如列表.字符串),enum ...
- jenkins 使用Git持续构建
为jenkins添加git插件. 在Available tab页中找到Git Plugin 点击下方的Install without Restart安装插件. 插件安装完毕后,我们需要在jenkins ...