跳到主要内容

社交信息流

查看此篇文档前,请先查看并了解好友关系文档中的单向关注关系。信息流是关注关系中,被关注者发布的状态信息汇集而成的「时间线」或者「朋友圈」内容。

基本概念

状态(Status)

指用户发出来的即时状态,例如微博中的一个帖子,微信朋友圈中的一段文字,就是这里所说的「状态」,我们用 Status 表示。

社交组件中的 Status 是指一条广义上的「状态」,它不仅可以表示某个用户更新了状态,还可以表示任意的一个事件,比如某人发布了一篇文章,对某张图片点赞等等。在控制台中对应的表名称为 _Status

时间线

在社交类产品中,用户 A 关注了一些人之后,他就可以按照时间顺序查看到那些人发布的各种「状态」信息(这里我们暂且把这些信息称为「时间线」);同样,A 发布了某一条「状态」之后,一般就会马上被关注 ta 的其他人看到,但是也有例外(就是接下来的「私信」)。

私信

是状态中的一类特殊信息,只发给特定的用户,不会进入关注者的时间线来公开展示,例如微博里面的「私信」即是如此。

信息流 API

我们的信息流 API 主要提供以下功能:

  • 用户 A 给用户 B 发送私信(发私信);
  • 用户 A 给关注 ta 的用户群体发送公开的状态信息(发推和转推,等);
  • 用户 B 可以查看别人给他发送的私信(私信列表);
  • 用户 B 可以查看 ta 关注的用户群体发出来的状态信息(查看时间线);
  • 用户 C 可以公开查看用户 A 发出去的所有公开的状态信息(查看单个用户的公开状态);
  • 用户 A 可以删除自己已经发布的状态,此时所有接收者的收件箱也会自动删除该状态数据
  • 用户 A 可以删除/屏蔽自己时间线上其他人发出来的状态(只在自己时间线上不显示,发布者和其他关注者依然可以看到)

以下的功能我们无法在基础 API 层面提供支持:

  • 用户 B 根据用户关系中的分组设置来查看不同的人发出来的状态信息;
  • 状态发出之后无法修改(可以通过删除 + 发布来实现);

同时,信息流 API 是与用户账号系统绑定以及好友关系 API 绑定的,如果不使用这些内置组件,将无法正常使用信息流功能。接下来我们通过一些例子,看看如何使用信息流 API 来完成产品开发。

特别提示:

发了一条状态,并不代表会自动发送了一条推送消息,开发者可以自由控制是否使用推送。更多信息请参考《推送通知服务总览》。

JavaScript SDK

状态

关注了用户之后(也就是成为他的粉丝),你就会接收到该用户发送给他的粉丝的状态信息。例如,我喜欢了某个视频,我可以发送这条信息「我喜欢了视频 xxxx」给我的粉丝。我的粉丝就可以在他们的收件箱(inbox)里收到这条状态信息。

发布状态

当前登录用户发送一条状态给关注他的粉丝:

var status = new AV.Status('视频url', '我喜欢了视频xxxx.');
status.set('sound', 'sound.wmv');
AV.Status.sendStatusToFollowers(status).then(function(status){
//发布状态成功,返回状态信息
console.dir(status);
}, function(err){
//发布失败
console.dir(err);
});

发布状态成功,粉丝的收件箱不一定马上能看到,因为发布过程是一个异步的过程,会有一定的延迟,通常这个延迟都在几秒之内。发送状态必须处于用户登录状态,使用 AV.Status.sendStatusToFollowers 将发送给登录用户的粉丝。

AV.Status 对象包含下列属性:

属性说明
id对象的objectId
messageId状态在某个用户收件箱的消息编号,发件箱返回的 status 则没有此属性,messageId 可用于 收件箱的分页查询
inboxType收件箱类型,默认是 timeline 收件箱,也就是 default。SDK 默认提供 private(私信),default 表示 timeline,你也可以自定义。
data状态属性,一个 JSON 对象,可通过 get 和 set 方法获取和设置。
createdAt消息的创建时间

其中 data.source 属性是保留属性,默认指向状态的发布者。

发送私信给某个用户

我还可以发送一条私信给单独某个用户:

var status = new AV.Status(null, '机密消息');
AV.Status.sendPrivateStatus(status,'52f9be45e4b035debf88b6e2').
then(function(status){
//发送成功
console.dir(status);
}, function(err){
//发布失败
console.dir(err);
});

AV.Status.sendPrivateStatus 的第二个参数指定私信接收的用户或者用户的 objectId。

发送给自定义收件箱

通过 send 方法还可以自定义 inboxType:

var status = new AV.Status(null, '我读了《clojure 编程乐趣》');
//定义一个 book 收件箱
status.inboxType = 'book';
status.send().then(function(status){
//发送成功
});

查询收件箱

查询我的 timeline 收件箱,可以通过 AV.Status.inboxQuery 方法:

var query = AV.Status.inboxQuery(AV.User.current());
query.find().then(function(statuses){
//查询成功,返回状态列表,每个对象都是 AV.Status
}, function(err){
//查询失败
console.dir(err);
});

收件箱返回的 status 列表,每个 status 都有 messageId 属性,表示这条 status 在这个收件箱里的唯一编号,AV.InboxQuery 有两个方法用于限制 messageId 的范围:

  • sinceId:设定查询返回的 status 的 messageId 必须大于传入的 messageId。
  • maxId:限定查询返回的 status 的 messageId 必须小于等于传入的 messageId。

通过 sinceId 和 maxId 可以实现分页查询:

查询本次查询之后新增的 status(向后翻页刷新):

//假设 messageId 是上次查询返回的 status 的最大 messageId 编号
var messageId = ...
var query = AV.Status.inboxQuery(AV.User.current());
query.sinceId(messageId);
//查询从上次查询返回结果之后的更新 status
query.find().then(function(statuses){
//查询成功,返回状态列表,每个对象都是 AV.Status
}, function(err){
//查询失败
console.dir(err);
});

查询本次查询的前一页(也就是更老的 status,向前翻页):

//假设 messageId 是上次查询返回的 status 的最大 messageId 编号
var messageId = ...
var query = AV.Status.inboxQuery(AV.User.current());
query.maxId(messageId);

AV.Status.inboxQuery 还可以指定收件箱的类型,默认是查询 timeline 收件箱,也可以查询私信收件箱:

var query = AV.Status.inboxQuery(AV.User.current(), 'private');

查询收件箱未读状态数目

使用 AV.Status.countUnreadStatuses 可以查询某个收件箱的未读状态数目和总数目:

AV.Status.countUnreadStatuses(AV.User.current()).then(function(result){
console.dir(result);
var total = result.total;
var unread = result.unread;
}, function(err){
//查询失败
});

同样的,你可以这样查询当前登录用户未读私信的未读数目和总数目:

AV.Status.countUnreadStatuses(AV.User.current(),'private').then(function(result){
console.dir(result);
var total = result.total;
var unread = result.unread;
}, function(err){
//查询失败
});

查询发件箱

查询我发出去的状态信息,可以通过 statusQuery 方法:

var query = AV.Status.statusQuery(AV.User.current());
query.find().then(function(statuses){
//查询成功,返回状态列表,每个对象都是 AV.Object
}, function(err){
//查询失败
console.dir(err);
});

AV.Status.statusQuery 返回的是一个普通的 AV.Query 对象,本质上是查询数据管理平台的 _Status 表。你可以自主添加更多查询条件。

iOS SDK

SDK 的安装参考 Objective-C 安装指南

状态

发布状态

发布一条时间线状态,即发一条我的粉丝可以看到的状态:

AVStatus *status=[[AVStatus alloc] init];

status.data=@{@"text":@"data type change"};

[AVUser logInWithUsername:@"travis" password:@"123456"];
[AVStatus sendStatusToFollowers:status andCallback:^(BOOL succeeded, NSError *error) {
NSLog(@"============ Send %@", [status debugDescription]);
}];

其中 status.data 可以任意指定 NSDictionary 数据。注意,这个字典中的 source 为系统保留字段,不可使用。

发私信

给某个用户发私信也非常简单:

AVStatus *status=[[AVStatus alloc] init];
status.data=@{@"text":@"this is a private message"};

NSString *userObjectId=@"XXXXXXXXXXXXX";

[AVStatus sendPrivateStatus:status toUserWithID:userObjectId andCallback:^(BOOL succeeded, NSError *error) {
NSLog(@"============ Send %@", [status debugDescription]);
}];

自定义状态

除了上面常见两种场景,自定义状态可以通过设置受众群体和发送者来实现更加灵活的功能。

AVStatus *status=[[AVStatus alloc] init];
[status setData:@{@"text":@"we have new website, take a look!",@"link":@"http://leancloud.cn"}];

status.type=@"system";

AVQuery *query=[AVUser query];
[query whereKey:@"age" equalTo:@(20)];
[status setQuery:query];

[status sendInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {

}];

上面是系统广播的基本实现。因为指定了一个 AVUser 查询,所以会发送给所有 age=20 的用户,指定了 type 是 system 或者任意字符串,则所有用户会在查询这个类型的状态中看到这一条。

获取状态

下面代码会获取用户时间线上的 50 条状态:

AVStatusQuery *query=[AVStatus inboxQuery:kAVStatusTypeTimeline];

//限制50条
query.limit=50;

//限制 1397 这个 messageId 上次查询的最大 messageId,如果不设置,默认为最新的
query.maxId=1397;

//需要同时附带发送者的数据
[query includeKey:@"source"];

[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
//获得 AVStatus 数组
}];

同理,可以获得用户的私信,只要把参数改为 kAVStatusTypePrivateMessage。返回的 AVStatus 对象有一个 messageId 属性,用于唯一表示这条 Status 在这个 inbox 里的标示符。可以用这个 id 结合 query 做分页查询。

AVStatusQuery 可以设置 sinceId 和 maxId:

  • sinceId:设定查询返回的 status 的 messageId 必须大于传入的 messageId。
  • maxId:限定查询返回的 status 的 messageId 必须小于等于传入的 messageId。

使用这两个 Id 就可以做分页查询。AVStatusQuery 查询不支持 skip

获取收件箱的未读 status 数目(从上次访问收件箱最新 status 到现在的未读 status 数目)可以使用 [AVStatus getUnreadStatusesCountWithType:andCallback] 方法。

下面的代码是某个用户发送出去的状态。查询发送出去的状态,是无法用 messageId(sinceId,maxId) 来做分片查询的。因为 messageId 只是相对于某个用户的 Inbox 才有意义, 同时返回的状态中也没有 messageId 的数据。

AVStatusQuery *query=[AVStatus statusQuery];

//设置查询某个用户,默认是查询当前用户
[query whereKey:@"source" equalTo:<AVUser>];

//限制条数
query.limit=20;

//设置消息类型
query.inboxType=kAVStatusTypeTimeline;

[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
//获得 AVStatus 数组
}];

Android SDK

SDK 的安装参考 Android 安装指南

信息流 API

假设我们要开发一个类似微博的产品,其中有用户 A 已经关注了 2 个用户(B 和 C),同时他有 3 个关注者(D、E、F)。

注意:以下示例代码基于 6.1.1 及以后版本开发。感兴趣的开发者可以参考我们的完整 demo: funny feed

发布状态

第一步,我们来看看用户 A 如何发布一条公开的「状态」。

构造 Status

开发者在 Status 中可以加入任意的数据,由应用层来对这些数据进行解析。信息流 API 提供了多种方式来构造一个 Status 实例:

class AVStatus {
// 完全空的 Status
AVStatus()
// 默认的支持图文混合的 Status
AVStatus(String imageUrl, String message)
// 附带其他自定义属性的 Status
AVStatus(Map<String, Object> customData)

// 设置与获取自定义属性
void put(String key, Object value)
Object get(String key)
// 删除某个自定义属性
void remove(String key)
}

使用方法在类的声明中应该可以一目了然。假如用户 A 想分享一下他中午吃的美食,那么可以按照如下方法来构造一条状态信息:

AVStatus status = new AVStatus("https://ww4.sinaimg.cn/bmiddle/691c275bgy1g9cdxpw3f4j21hc1hc4qq.jpg", "北京烤鸭,贼拉好吃");
status.put("location", "铁岭市赵大胡同");

这一条 Status 如果以公开的方式发送出去,所有关注 A 的用户都会看到这条信息。如果 A 只想发送给用户 D ,他可以选择私信的方式来发送,那就只有用户 D 可以查看到了(这两种方式下一节会说明)。

AVStatus 类中有如下属性被系统保留了:

  • inboxType,String,表示发布时指定的访问类型,目前有 privatedefault 两种类型。
    • private 表示是私信,不会公开显示;
    • default 表示是公开信息,会进入到关注者的时间线;
    • 默认值为 default
    • 开发者可以在应用层面扩展这个 inboxType。例如,微博上就有「系统通知」这一类消息,我们可以增加一种「notification」的 inboxType,来实现这一类消息的收发展示。
  • source,Pointer,指向状态发布者(AVUser)的指针
  • messageId,Integer,LeanCloud 服务端在将状态插入目标用户的接收队列时,生成的一个序列号,主要用于状态流的分页遍历(这在后面会说明)。
  • updatedAt, createdAt, objectId,这些 AVObject 通用属性。

这些属性都可以通过 getter/setter 方法进行访问。

发送 Status

我们提供了三种方式来发送 Status:

class Status {
public Observable<AVStatus> sendToFollowersInBackground();
public Observable<AVStatus> sendToFollowersInBackground(String inboxType);
public Observable<AVStatus> sendToUsersInBackground(AVQuery query);
public Observable<AVStatus> sendToUsersInBackground(String inboxType, AVQuery query);
public Observable<AVStatus> sendPrivatelyInBackground(final String receiverObjectId);
}

分别对应不同的使用场景:

  • 直接发布给用户自己的关注者(sendToFollowersInBackground())。

这是最常见的方式,用户 A 完成 Status 的构造之后,直接就公开发布出去。这条 Status 就会自动进入关注 ta 的用户的时间线。

另外,考虑到应用层对 inboxType 扩展的需要,我们还提供了一个指定 inboxType 的公开发布 Status 的方法:sendToFollowersInBackground(String inboxType),供开发者按需选择使用。

  • 选择性的发布给某些用户(sendToUsersInBackground(AVQuery query))。

用户 A 可能会有这样的需求,希望自己发布的 Status 只被一部分好友看到,这时候就可以在发布 Status 的时候,指定一个 AVQuery 实例来圈定目标用户。这是一种比较高阶的做法,具体细节后面会进行详细说明。

  • 以私信的形式单独发送给某个用户(sendPrivatelyInBackground(final String receiverObjectId))。

这也是比较常见的需求,某条 Status 只定向发送给某个好友,这时候默认就转变成了「私信」。

我们还是回头来看用户 A 发送美食帖子的实现方法。假设 A 就是公开发布给所有的关注者,那么只需要一次调用就可以完成目的:

status.sendToFollowersInBackground()
.subscribe(new Observer<AVStatus>() {
@Override
public void onSubscribe(Disposable disposable) {
}

@Override
public void onNext(AVStatus avNull) {
// succeed
}

@Override
public void onError(Throwable throwable) {
// failed
throwable.printStackTrace();
}

@Override
public void onComplete() {
}
});

当然,这里有一个前提是用户 A 已经完成了登录,就是 AVUser.currentUser 必须存在且是登录状态,否则发送会失败。

查看 Status

用户 A 发布了状态之后,关注 ta 的用户 D 该如何查看这些信息呢?我们提供了多种方法,可以来查询和展示 Status。

查看自己的时间线

假设用户 D 要查看自己的时间线,他首先需要登录,然后可以调用如下方法来查询自己的时间线状态:

AVUser userD = AVUser.currentUser();
String defaultInbox = AVStatus.INBOX_TYPE.TIMELINE.toString(); // "default"
AVStatusQuery statusQuery = AVStatus.inboxQuery(userD, defaultInbox);
statusQuery.findInBackground().subscribe(new Observer<List<AVStatus>>() {
@Override
public void onSubscribe(Disposable disposable) {
}

@Override
public void onNext(List<AVStatus> avStatuses) {
// succeed
// 这时候每一个 AVStatus 实例都会有 source,messageId,objectId,createdAt,inboxType 等预留属性,也会有开发者自定义设置的所有属性值。
}

@Override
public void onError(Throwable throwable) {
// failed.
throwable.printStackTrace();
}

@Override
public void onComplete() {
}
});
查看私信

用户 D 要查看自己的私信列表,其方法与查看时间线类似,只需要把 inboxType 变为 AVStatus.INBOX_TYPE.PRIVATE 即可,示例代码如下:

AVUser userD = AVUser.currentUser();
String inboxType = AVStatus.INBOX_TYPE.PRIVATE.toString(); // "private"
AVStatusQuery statusQuery = AVStatus.inboxQuery(userD, inboxType);
statusQuery.findInBackground().blockingLast();
查看单个用户的公开 Status

查询时间线和私信都需要当前用户是登录状态,且只能查询当前登录用户能接收到状态流。有时候我们产品里还需要展示单个用户发布的所有公开状态,例如微博的个人主页上会展示 ta 发布的所有帖子。

要查看目标用户的公开 Status,并不要求该用户当前是登录状态,我们只需要知道目标用户的 objectId(AVUser 的基本属性之一) 就可以查看 ta 的公开状态了。

示例代码如下:

AVUser targetUser = AVObject.createWithoutData(AVUser.class, targetUserObjectId);
AVStatus.statusQuery(targetUser)
.findInBackground()
.subscribe(new Observer<List<AVStatus>>() {
@Override
public void onSubscribe(Disposable disposable) {
}

@Override
public void onNext(List<AVStatus> avStatuses) {
// succeed
// 这时候每一个 AVStatus 实例都会有 source,messageId,objectId,createdAt,inboxType
// 等预留属性,也会有开发者自定义设置的所有属性值。
}

@Override
public void onError(Throwable throwable) {
// failed
throwable.printStackTrace();
}

@Override
public void onComplete() {
}
});
Status 的分页展示

从上面的示例代码可以看到,我们可以通过 StatusQuery 实例来完成多种 Status 数据查询,查询结果里所有 Status 实例按照发布时间从新到旧的顺序进行排列。不过如果 Status 数据量较大,无法一次查询(默认 100 条)获取全部数据,这时候就需要进行分页查询,我们该如何做呢?

StatusQuery 还提供了分页获取结果的方法:nextInBackground,它可以在当前查询的基础上,继续往后获取结果数据。例如,用户 D 使用前述的接口获取了头 100 条结果之后,要继续拉取时间线数据,可以这样做:

// AVStatusQuery statusQuery = AVStatus.inboxQuery(userD, defaultInbox);
statusQuery.nextInBackground().subscribe(new Observer<List<AVStatus>>() {
@Override
public void onSubscribe(Disposable disposable) {
}

@Override
public void onNext(List<AVStatus> avStatuses) {
// succeed
// 这时候每一个 AVStatus 实例都会有 source,messageId,objectId,createdAt,inboxType 等预留属性,也会有开发者自定义设置的所有属性值。
}

@Override
public void onError(Throwable throwable) {
// failed.
throwable.printStackTrace();
}

@Override
public void onComplete() {
}
});

nextInBackground() 可以一直调用,直到没有新的结果返回为止。

分页查询的其他参数设置

StatusQuery 默认都是按照从新到旧的顺序来查询结果,并且每次查询默认的结果集大小为 100。实际上,StatusQuery 还允许开发者来设置多种查询参数,如:

  • 查询方向。可以通过 setDirection(PaginationDirection direct) 方法来设置是从新往旧查询(最近发布的 Status 会最先返回),还是从旧到新查询 Status 数据(最早发布的 Status 会最先返回)。
  • 分页大小。可以通过 setPageSize(int pageSize) 方法来设置分页的大小,允许的页面大小区间为 (0,1000)(不包含两个端点)。
  • 查询的起点和终点。在对时间线进行分页查询的时候,还允许开发者设置查询起点和终点 Status 的 MessageId(查询结果中不会包含两个端点的数据)。
    • setSinceId(long sinceId) 用来设置结果集中最小的 messageId,返回的所有 Status 的 messageId 都会比 sinceId 大。
    • setMaxId(long maxId) 用来设置结果集中最大的 messageId,返回的所有 Status 的 messageId 都会比 maxId 小。

如果用户 D 需要按照从旧到新的顺序浏览时间线 Status,并且每次只希望看 20 条数据,那么可以这样实现:

AVUser userD = AVUser.currentUser();
String defaultInbox = AVStatus.INBOX_TYPE.TIMELINE.toString(); // "default"
AVStatusQuery statusQuery = AVStatus.inboxQuery(userD, defaultInbox);
statusQuery.setPageSize(20);
statusQuery.setDirection(PaginationDirection.OLD_TO_NEW);
List<AVStatus> first20Statuses = statusQuery.findInBackground().blockingLast();
List<AVStatus> second20Statuses = statusQuery.nextInBackground().blockingLast();
状态流的计数信息

与 Query 类似,StatusQuery 提供以下方法:

Observable<Integer> countInBackground()

来查询符合条件的 Status 数量,这可以用来查询单个用户的公开 Status 总数。

对于时间线的计数,就不能使用上面的方法了。对于时间线中 Status 的计数信息,因为后端的查询方式不一样,同时也由于产品层对查询结果的要求不一样(需要返回总数和未读数两个维度的统计信息),StatusQuery 提供了新的方法来查询计数信息:

Observable<JSONObject> unreadCountInBackground()

该函数的返回值是一个 JSONObject,包含 totalunread 两个计数值。

例如,用户 D 要查看自己收到的私信的计数信息,可以按照如下办法来查询:

AVUser userD = AVUser.currentUser();
AVStatus.inboxQuery(userD, AVStatus.INBOX_TYPE.PRIVATE.toString())
.unreadCountInBackground()
.subscribe(new Observer<JSONObject>() {
@Override
public void onSubscribe(Disposable disposable) {

}

@Override
public void onNext(JSONObject jsonObject) {
// succeed.
}

@Override
public void onError(Throwable throwable) {
// failed.
}

@Override
public void onComplete() {
}
});

要展示用户 A 发布的状态总数,可以按照如下办法来查询:

AVUser targetUser = AVObject.createWithoutData(AVUser.class, userAObjectId);
AVStatus.statusQuery(targetUser)
.countInBackground()
.subscribe(new Observer<Integer>() {
@Override
public void onSubscribe(Disposable disposable) {
}

@Override
public void onNext(Integer integer) {
}

@Override
public void onError(Throwable throwable) {
}

@Override
public void onComplete() {
}
});

删除 Status

我们提供删除 Status 的接口,但是只在以下条件满足的时候调用才会成功:

  • 当前用户必须是登录状态。
  • 当前登录用户可以删除自己发布的 Status,此时 Status 会从源头上被删除,当前用户的关注者时间线上就不会再出现这条 Status。
  • 当前登录用户可以删除自己时间线上他人发布的 Status,此时 Status 不会从源头上被删除,其他关注者在自己的时间线上依然可以看到这条 Status。

Status 的删除接口如下:

Observable<AVNull> deleteInBackground();
删除自己发布的 Status

假设用户 A 发出那条美食的帖子之后,觉得图片不够精美,想删除它,那么在客户端可以这样执行删除:

// AVStatus target = ...;
target.deleteInBackground()
.subscribe(new Observer<AVNull>() {
@Override
public void onSubscribe(Disposable disposable) {
}

@Override
public void onNext(AVNull v) {
// succeed
}

@Override
public void onError(Throwable throwable) {
// failed
}

@Override
public void onComplete() {
}
})
屏蔽别人发布的 Status

假设用户 A 发出那条美食的帖子之后,ta 自己没有删除,但是 ta 的关注者 D 在时间线上看到之后,想屏蔽这一条 Status,那么在客户端可以这样执行删除:

// AVStatus target = ...;
target.deleteInBackground()
.subscribe(new Observer<AVNull>() {
@Override
public void onSubscribe(Disposable disposable) {
}

@Override
public void onNext(AVNull v) {
// succeed
}

@Override
public void onError(Throwable throwable) {
// failed
}

@Override
public void onComplete() {
}
})

可以看到,Status 的删除方式都是一样的,区别只在于当前登录用户是否拥有所有权:

  • 如果是当前用户自己发布的 Status,会从源头上进行删除;
  • 如果只是存在于当前用户的时间线上,则只会从当前用户的时间线上进行删除;
  • 其他情况下,当前用户无权进行删除操作,调用会报错;

REST API

再次解释下术语定义:

  • status:一条状态,包含两个预定义属性 messageIdinboxType,其他属性都可自定义。
  • target:状态的目标接收者,也就是 inbox 的 owner。
  • inbox:target 的收件箱,有 owner(所有者)和 inboxType(收件箱类型)两个属性。

发布 Status API

调用 API 如下:

POST /statuses

接受的 JSON 对象参数:

属性说明
query查询 target 的条件,包括下列属性:
  • where:查询条件,可为空 {},表示查询全表。
  • className:target 的 className
  • keys:查询指定的列作为 inbox 的 owner 属性存储,如果不指定,默认将为整个对象作为 pointer 存储到 owner。
datastatus 的 数据 JSON 对象,用户自定义。如果包含 source(指向发送者的 Pointer),并且 inboxType 设为 default,该 status 会同时往发送者的 inbox 投递。
inboxType字符串,指定接收这条 status 的 inbox 类型,可为空,默认为 default

【示例一】往 dennis 的粉丝群体发送一条状态:

curl -X POST \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
-H "Content-Type: application/json" \
-d '{
"data": {
"image": "paas-files.qiniudn.comwQUf3WohbJpyuXutPjKHPmkSj4gbiYMeNJmTulNo.jpg",
"message": "AVOS Cloud is great!"
},
"inboxType": "default",
"query": {
"className": "_Follower",
"keys": "follower",
"where": {
"user": {
"__type": "Pointer",
"className": "_User",
"objectId": "dennis'id"
}
}
}
}' \
https://{{host}}/1.1/statuses

这条状态的内容是 data 指定的,并且设定 inboxType 是 default

{
"image": "paas-files.qiniudn.comwQUf3WohbJpyuXutPjKHPmkSj4gbiYMeNJmTulNo.jpg",
"message": "LeanCloud is great!"
}

这条状态的目标用户群体是 query 指定的查询条件,查询的是 _Follower 表中 dennis 的粉丝用户。

【示例二】dennis 向 catty 发送私信的请求类似:

{
"data": {
"message": "hello catty!"
},
"inboxType": "private",
"query": {
"className": "_User",
"where": {
"objectId": "catty's id"
}
}
}

查询发出的状态 API

GET /statuses

跟查询其他对象一样。知道 objectId,查询单条状态:

GET /statuses/:status_id

删除状态 API

DELETE /statuses/:status_id

查询已经关注的用户的状态聚合列表 API

查询我关注的用户发出来的状态聚合而成的列表,也就是查询自己的收件箱,通过:

GET /subscribe/statuses

接收参数(参数都必须要 URL encoded):

参数说明
ownerJSON 序列化后的 owner 字符串,表示 inbox 所有者。
inboxTypeinbox 的类型,默认为 default,可为空。
where用于过滤 status 的 where 条件,也是 JSON 序列化后的字符串。
sinceId查询返回的 status 的 messageId 必须大于 sinceId,默认为 0。
maxId查询返回的 status 的 messageId 必须小于等于 maxId,默认为 0。
limit最多返回多少条 status,默认 100,最大 100。
count默认为空,设置为 "1" 表示在结果中带上 status 的 count 计数。

【示例一】查询我的主页 timeline:

curl -X GET \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
-H "Content-Type: application/json" \
-G \
--data-urlencode 'owner={"__type":"Pointer","className":"_User","objectId":"51c3ba67e4b0f0e851c16221"}' \
https://{{host}}/1.1/subscribe/statuses

【示例二】查询我的最新私信列表:

    --data-urlencode 'owner={"__type":"Pointer","className":"_User","objectId":"51c3ba67e4b0f0e851c16221"}' \
--data-urlencode 'inboxType=private'

【示例三】假设上次返回的最大 messageId 是 99,查询从 mesageId = 99 开始最新的 status:

    --data-urlencode 'owner={"__type":"Pointer", "className":"_User","objectId":"51c3ba67e4b0f0e851c16221"}' \
--data-urlencode 'sinceId=99'

【示例四】查询 messageId 在 99 到 199 之间的 status:

    --data-urlencode 'owner={"__type":"Pointer","className":"_User","objectId":"51c3ba67e4b0f0e851c16221"}' \
--data-urlencode 'sinceId=99' \
--data-urlencode 'maxId=199'

【示例五】查询最新的 status,并且 status 的 image 属性存在,也就是查询包含图片的最新 status:

    --data-urlencode 'owner={"__type":"Pointer","className":"_User","objectId":"51c3ba67e4b0f0e851c16221"}' \
--data-urlencode 'where={"image":{"$exists":true }}'

删除收件箱里的消息

可以根据 messageId 来删除收件箱的消息:

curl -X DELETE \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
-H "Content-Type: application/json" \
-G \
--data-urlencode 'owner={"__type":"Pointer","className":"_User","objectId":"51c3ba67e4b0f0e851c16221"}' \
--data-urlencode 'inboxType=default' \
--data-urlencode 'messageId=99' \
https://{{host}}/1.1/subscribe/statuses/inbox
参数说明
ownerJSON 序列化后的 owner 字符串,表示 inbox 所有者。
inboxTypeinbox 的类型,默认为 default,可为空。
messageId想要删除的 status 的 messageId

查询状态计数 API

查询 inbox 总消息数目和未读消息数目:

GET "/subscribe/statuses/count

可指定的条件:

  • owner:JSON 序列化后的 owner 字符串,表示 inbox 所有者。
  • inboxType:inbox 类型,默认为 default,可为空。

【示例一】查询我的未读消息数目:

curl -X GET \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
-H "Content-Type: application/json" \
-G \
--data-urlencode 'owner={"__type":"Pointer","className":"_User","objectId":"51c3ba67e4b0f0e851c16221"}' \
https://{{host}}/1.1/subscribe/statuses/count

返回:

{ "total": 100, "unread":20}

【示例二】查询私信消息数目:

curl -X GET \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
-H "Content-Type: application/json" \
-G \
--data-urlencode 'owner={"__type":"Pointer","className":"_User","objectId":"51c3ba67e4b0f0e851c16221"}' \
--data-urlencode 'inboxType=private' \
https://{{host}}/1.1/subscribe/statuses/count

重置未读消息数

如果想将某个收件箱的未读消息数设置为 0,也就是通常看到的将全部消息设为「已读」的功能,可以通过 resetUnreadCount API 来实现:

curl -X POST \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
-H "Content-Type: application/json" \
-G \
--data-urlencode 'owner={"__type":"Pointer","className":"_User","objectId":"51c3ba67e4b0f0e851c16221"}' \
--data-urlencode 'inboxType=private' \
https://{{host}}/1.1/subscribe/statuses/resetUnreadCount

接收的参数与 查询状态计数 API 是一致的。