Z'zyc

我是一名iOS开发者,我是一名非计算机专业出生的程序员。

你可以通过 1748439277@qq.com 联系我

Z'zyc

我是一名iOS开发者,我是一名非计算机专业出生的程序员。

如果学习很幸苦,那就尝试无知的代价

开动你的小手,nwjs 实现FTP客户端
2020-05-14 技术分享 阅 1604

前言

基于什么目的我会手动开发一个 FTP 客户端呢?其实,很简单,爱折腾,如果不是喜欢折腾,可能就不会对软件开发如此痴迷,对其中的实现原理如此痴迷,一个不喜欢折腾的程序员,可能会失去方向感。最近公司集成第三方厂商的业务越来越多,SDK 也越来越大,SVN 服务器不允许对超过 50 MB以上的 SDK 进行管理,那我们将这些 SDK 放哪儿呢?没错,就是 FTP 服务器,过去的半年我作为 Mac 的用户使用 FTP 体验极其糟糕,系统的 Finder 访问 FTP 服务器无法访问,线上的软件也没找到合适的,半年下来我捣鼓了虚拟机,装了 Window10 ,在 Mac 和 Window10 之间,常年处于无缝切换的状态。

事实上,出于对原理的好奇,决定动手开发 FTP 客户端,开发过程总共 20 小时,大约 4 个晚上,中间也遇到过问题,也一并解决,整个儿过程下来,收获颇丰。

基本功能概览

客户端下载地址

  • FTP 文件导航
  • 文件下载
  • 删除文件
  • 右键文件上传
  • 右键新增文件夹

技术选型

FTP 业务的核心,一定是与服务器的连接,在 gihtub 上找到了一个 4 年前的产物“node-ftp”。

整体文档上看下来,功能齐全,手动测试了下,可以正常访问 FTP 服务器,于是就决定使用该模块。(这里有一个小问题,我没有全面测试 API,只测了一个连接的 API,导致在后续开发过程中使用 API 的时候 产生中文编码问题,这里体现了技术调研,一定要严谨,仔细)

客户端容器使用 nwjs(node-webkit),实际上我对这个技术关注已久,一直没有机会能够动手实践一下,这回终于让我用上了,nwjs 实际上是一个 Hybrid App,你可以直接在容器中使用 nodejs 的 API 作为 Native Code,还是很爽的。

表现层,我则使用了 Vue+ElmemtUI,当下最火,开发效率高,非他们莫属。

开始开发

废话不说,直接上手干,在网上找了一款现成的 Vue+ElementUI 后台项目模版,一顿npm install、npm run serve,将项目运行出来,迅速将模版中不需要的模块删除,一番操作后,就遇到了第一个问题,Vue 的工程里不能直接用 nodejs?使用npm run serve启动了本地的开发服务,哦!?,需要将地址跑在 nwjs 里才行吧,于是前往 nwjs.io 的官网,看了下文档后,开启了remote-debug模式,然后把地址放在调试模式的容器中跑起来,这下应该成功了吧?,一运行,还是报红,后来我仔细想了下,Webpack 有一个编译过程,如果在 Vue 的工程中直接写 nodejs 的代码,可能会被编译 es5 其他的语法,机智如我,于是我在 public 目录下新增 NWBridge.js 文件,在 index.html 主动引入文件,该文件负责连接 Vue 的事件和 nodejs 的 API,再次运行,再次用remote-debug运行,还是不行,理论上这次应该是成功的,但是并没有,我又想了下,是不是 nwjs 不允许在线地址调用 nodejs,我打开 nwjs 的 DevTool,输入了location.href=开发地址,这次直接跑起来,但是 nodejs 的 API 依旧没有调用成功,只剩下最后一招,只能打成 nwjs 本地调试包,利用命令执行,接下来就是使用npm run build,然后增加 package.json 文件,新增一个 nwjs 的开发目录 nw,将生成的源码包和 package.json 文件放进去,然后利用全局命令nwjs ./nw,这一次运行成功,nodejs API 也调用成功了,心里大喜,但是一想,每次修改东西都需要干这件事情,太复杂,能不能将这件事情自动化,于是我就修改了npm run build命令,变成了如下(vue-cli-service build)&&(rm -rf ./nw/dist)&&(mv dist ./nw)&&(nwjs ./nw)一顿操作,搞定,这样每次修改完后,只需要执行npm run build就可以预览、调试了,到此,开发环境算是搭建好了。

页面的怎么开发的,就不说了,工作量也不多无非就那么几下,接下来准备对接第一个 API ,显示目标服务器的目录,一顿捣鼓后,就有了如下效果:

很开心,于是对接各个模块的点击,进入子目录,这时候遇到了严重的问题,中文目录无法访问,点击无效果,这个问题我花的时间最长,解决花了 6 个小时,这里要注意我们一开始是拿不到中文目录的,现在能看到中文是因为我使用了iconv-lite模块,对其进行 GBK 转 UTF-8 编码,所以可以看到中文目录,FTP 的服务器一定是个 Window 服务器,因为 GBK 只有 Window 才有,而 nodejs 中不支持 GBK,所以需要这个著名的库iconv-lite。到目前为止,表现层可能无法解决这个问题了,于是我将内容最小化,利用 js 脚本直接执行中文命令,我发现不行,并不能访问,所以不得不读 node-ftp 的源码,源码比较少,我花了两个小时就看完了,我发现其原理和 smtp、iamp 类似,同样是架起 socket 连接指定服务器,然后向管道里写入 FTP 标准的指令,例如LIST命令,到这里我突然理解,管道写过来的是 GBK,写回去的一定也是 GBK 才行,于是修改源代码,将管道统一写回的地方,利用iconv-lite进行一层转换,可发现还是不行,于是我就取回管道过来的中文字节,对其中的中文字节手动筛选,找到指定文件名的中文变量,将字节原封不动的从管道写回去,这一次,成功了!!,这证明理论没错,于是我再次对写死的中文,通过一层转换写回管道,可还是不行,这次又是为什么呢?无奈,再次排查后,发现我直接用写死的‘中文字符串’,转换出来的字节和从FTP管道写回来的中文参数转换出来的字节,差了一位,就因为一位导致无法执行命令,于是这一次,我直接用FTP管道写回的中文变量,再次访问其子目录,果然这一次成功了。

放一张成功的图,成功进入其他子目录。

上述问题解决后,基本没有大问题了,于是开始开发剩下的内容,其中包括上传文件、下载文件、删除文件、新增文件夹、导航栏面包屑、FTP记录读写等,这其中下载文件遇到一个问题,文件保存对话框如何打开,因为<input type='file' />标签只负责选择上传文件操作,到这里我想到 nwjs 容器应该会提供对应的方法,于是又再次前往 nwjs.io 官网阅读文档,果然让我找到了如下内容:

果然 nwjs 对 input 标签进行重载,让他支持了文件另存为,OK!!到此功能全部完成,最后开始打包我们的 App。

总结

为什么我需要去做这件事情,因为有计划就需要付诸实践,否则想法只能留在脑海里,nwjs 就留了很久,而做完这件事情后,我又发现自己对 Hybrid App 的理解更加深刻,作为程序员,主动性驱动很重要,一定要主动的发现需求,发现问题,主动的去沟通,去交互,程序员之间无非就是比谁先踏出自己的一亩三分地,谁先主动行动,谁才能收获更多。