1、使用ssh的好处
通过使用SSH,你可以把所有传输的数据进行加密,这样"中间人"这种攻击方式就不可能实现了,而且也能够防止DNS欺骗和IP欺骗。使用SSH,还有一个额外的好处就是传输的数据是经过压缩的,所以可以加快传输的速度。
所谓“中间人”的攻击方式, 就是“中间人”冒充真正的服务器接收你传给服务器的数据,然后再冒充你把数据传给真正的服务器。服务器和你之间的数据传送被“中间人”一转手做了手脚之后,就会出现很严重的问题。
2、上传和下载要解决的两个问题:
- 上传(下载)的实现过程
- 在上传(下载)的过程中,前端需要知道上传的进度,更新进度条;在上传(下载)结束后,前端需要知道上传已经结束,更新上传数量
3、上传(下载)过程:
1)上传前的操作
在上传之前,我们要获取这几个参数:
- 被上传的文件在本地电脑的存储路径(绝对路径,包含文件名及后缀);
- 要上传的目的地的路径(远程端的路径,包含文件名及后缀),存到哪里;
- 一个用于上传的server对象,其中包括ip、port、username、password
2)调用服务端上传方法
在前端调用 Meteor.call,通知服务端相应的上传方法,并把上述参数传给服务端,去做上传
3)服务端执行上传(下载)
1、实现上传(下载)我们需要借助一个依赖包ssh2-sftp-client。
所以先下载它。
npm install ssh2-sftp-client
2、引入
let sftpClient = require('ssh2-sftp-client');
3、创建一个sftp对象
let sftp = new sftpClient();
4、上传的过程
sftp.connect({
host: '127.0.0.1',
port: '8080',
username: 'username',
password: '******'
}).then(() => {
return sftp.fastPut(localPath,remotePath, {step: (total_transferred, chunk, total) => {
//每小段上传完成后的回调
}})
})
.then(data => {
console.log( '上传结束',data);
sftp.end();
}).catch(err => {
console.log('上传出现错误',err);
sftp.end();
});
- 1)建立ssh连接,调用sftp.connect(server)方法,并传入server对象
- 2)执行上传,sftp.connect()返回一个Promise对象,在第一个then中,调用sftp.fastPut执行上传文件的操作
fastPut方法只是其中的一种上传方法,ssh包还提供有其它的上传方法。
fastPut(localPath, remotePath, options) ==> string
fastPut方法共有三个参数
-
localPath为本地文件的路径
-
remotePath为远程的路径(目的地的路径)
-
options为配置对象
options共有四个属性,其中step属性的值是一个方法。文件上传操作并不是一次性完成的,而是将一个大文件分成一小块一小块上传,所以每一小块上传完成后就调用一次这个方法。
在上传过程中会多次调用这个step方法。
step方法共有三个参数- total_transferred,已经上传了多少k(包含本次上传的)
- chunk,本次上传了多少k
- total,此文件一共有多少k
-
3)当全部上传完成后,就执行第二个then中的回调方法。
-
回调的参数data是一个字符串,告诉你上传的结果,文件从哪上传到哪成功了。例如‘ E:\work\sg2148_MPanelCtl\img\Diagonal-45FoV-left.bmp was successfully uploaded to /opt/seeing/app/rgb_config/images/Diagonal-45FoV-left.bmp!’
在里面调用end方法,结束ssh -
4)当catch到error时也end结束ssh。
5、下载的过程
下载的过程同上传的过程类似
let sftp = new sftpClient();
sftp.connect(server).then(() => {
return sftp.fastGet(remotePath, localPath,{step: (total_transferred, chunk, total,) => {
//每小段下载完成后的回调
}});
}).then(() =>{
console.log("下载结束");
sftp.end();
}).catch((err) => {
console.log('下载出现错误',err);
sftp.end();
});
下载使用的是sftp.fastGet方法,并且其参数的顺序与上传不同
第一个参数是远程的路径
第二个参数是本地的路径
总之无论上传还是下载方法,其第一个参数都是从哪里的地址,第二个参数是到哪里的地址。
4、前端如何知道每个文件上传的进度
上传一个文件是分多块上传的,每上传一小块就调用一次step函数。并且step函数的参数中含有已经上传完成的体积大小。
1、第一种方法,前端轮询数据库
在服务端每次调用step函数时,都将上传的进度更新到数据库;然后在前端向数据库轮询,当上传完成时resolve出去。
但我在项目中发现,服务端更新数据库有时会存在bug,数据更新不上,即使改成递归的更新数据库(即更新数据库不成功,就再次更新,直到更新成功为之),但还是偶尔有问题。
2、第二种,使用socket通知
服务端在step函数中向前端发消息,在传输完成时向前端发消息,在传输遇到错误时向前端发消息;前端根据这些消息做相应的处理。具体操作已在另一篇文章详述。