简介

七牛云 的内容管理默认没有文件的缩略图,如果我们想找某一张图片就会很头疼,所以我用Meteor做了一个小的demo,用来显示文件的缩略图,并有删除、移动、复制、下载等基本的操作功能。对于其中的错误处理,遇到了一些问题,在这里总结一下。

demo图片:

qiniu-manager
qiniu-manager

服务器端异步回调函数

Meteor中,我们不能直接在Meteor.method()方法里调用异步函数,会报错,根据提示信息,我们可以用Meteor.bindEnvironment(function(err, ret){}这样的方式来绑定异步函数,不过在Atmospherejs上,已经有现成的包来提供更优雅的方式,就是meteorhacks:async。例如在imports/api/method.js中,对于下面的代码:

1
2
3
4
5
6
7
8
9
10
11
12
'resources.remove' (id, bucket, key) {
const client = new qiniu.rs.Client();
client.remove(bucket, key, Meteor.bindEnvironment(function(err, ret) {
if (!err) {
console.log('Meteor method resources.remove success');
Resources.remove({ _id: id });
} else {
console.log('Meteor method resources.remove---->');
console.log(err);
}
}));
},

我们可以改写成:

1
2
3
4
5
6
7
'resources.remove' (id, bucket, key) {
const client = new qiniu.rs.Client();
let wrapQiniuClient = Async.wrap(client, ['remove','stat','move','copy']);
wrapQiniuClient.remove(bucket, key);
console.log('Meteor method resources.remove success');
Resources.remove({ _id: id });
}

错误处理

对于第一种方式,由于包裹在client.remove()里,错误信息不能直接回传到客户端,导致浏览器中没有错误提示。于是想到新建一个Errors数据库,如果有错误,就存到数据库,并且客户端订阅后,可以得到错误信息。

1
2
3
4
5
6
else {
console.log('Meteor method resources.remove---->');
// 在这里把错误信息存入数据库
Errors.insert({err: err.error,code: err.code});
console.log(err);
}

但是,有一些问题,比如在客户端执行Meteor.call('resources.remove'),我们不能判断是否调用成功,因为服务器端无法处理错误。这样我们就不能写逻辑:调用成功,返回到主页面,调用失败,显示错误信息。

对于第二种方式,我一开始没有正确的理解,也没有找到正确的方法。后来想到可以用try/catch语法,就赶紧试了一下,于是代码变成了:

1
2
3
4
5
6
7
8
try {
wrapQiniuClient.remove(bucket, key);
console.log('Meteor method resources.remove success');
Resources.remove({ _id: id });
} catch (err) {
console.log(err);
throw new Meteor.Error('removeError', err);
}

注意,这里我们抛出错误,客户端是可以接收到的,我们的处理逻辑也通顺了,在imports/ui/template/detail.js中:

1
2
3
4
5
6
7
8
9
10
Meteor.call('resources.remove', id, bucket, key, (err) => {
if (err) {
console.log('resources.remove---->');
console.log(err.reason);
instance.error.set('error', err.reason);
} else {
console.log('resources.remove success');
FlowRouter.go('/main');
}
});

我们把错误信息存到ReactiveDict里,在helpers中取出来:

1
2
3
4
5
6
7
8
9
10
Template.detail.helpers({
error() {
const instance = Template.instance();
const error = instance.error.get('error');
if (!isEmpty(error)) {
$('.err').show();
$('.err').fadeOut(5000);
return error;
}
},

模板文件里detail.html:

1
<h3 class="err">操作失败:{{error.error}} 错误码:{{error.code}}</h3>

这样,当有错误时,我们简单的用jquery来显示。

小的问题

尝试了几次之后,发现了一个问题,第一次的错误信息可以正常显示,而以后的错误信息不会再显示了,查找原因后发现,在调用Meteor.call()之前,我们要把ReactiveDict里的值设置为空,然后就能正常工作了:

1
instance.error.set('error', '');

另外,我们也可以定义一个操作成功的提示信息,方法相同,这里就不在赘述了,不过注意这里也需要先设置为空,如:

1
instance.success.set('success', '');

最后

如果大家看的不是很明白,可以直接看源码,项目地址:qiniu-manager