Skip to content

Commit 8d5ba16

Browse files
wangxiaoleeyeh
authored andcommitted
Get API server from cache first. (#309)
* fix doc link * Add more warning for AV.initialize() . * Add sync function for getting local storage. * Get API server from cache first. * Readme add install part. * Add async get API Host from cache * fix install name * getServerUrl -> refreshServerUrl * Add set and setAsync to Cache module * Add Cache module unit test * Must run getServerURL() before all request. * Promise -> AVPromise * Remove cache async function * fix typo
1 parent 72469b4 commit 8d5ba16

File tree

5 files changed

+102
-75
lines changed

5 files changed

+102
-75
lines changed

README.md

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,15 @@ JavaScript SDK for [LeanCloud](http://leancloud.cn/).
44

55
## 使用方法请看 [官方文档](https://leancloud.cn/docs/leanstorage_guide-js.html)
66

7-
## 版本说明
7+
## 安装
88

9-
* 0.x.y 版本,是不兼容 React Native 运行时的老版本 SDK,相对稳定,云引擎主要依赖这个分支版本。
10-
* 1.0.0-x 版本,是我们最新开发的兼容 React Native 运行时的版本,处于开放测试阶段,欢迎大家尝试。我们最终将使用这个分支替代云引擎里的 `0.x.y` 版本。
9+
```
10+
// npm 安装
11+
npm install leancloud-storage --save
1112
12-
可以使用以下命令安装 1.0.0-x 版本:`npm install avoscloud-sdk@next`
13+
// bower 安装
14+
bower install leancloud-storage --save
15+
```
1316

1417
## 贡献代码
1518

src/cache.js

Lines changed: 23 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -6,27 +6,31 @@
66
const storage = require('./localstorage');
77
const AV = require('./av');
88

9-
const remove = exports.remove = storage.removeItemAsync.bind(storage);
9+
const removeAsync = exports.removeAsync = storage.removeItemAsync.bind(storage);
1010

11-
exports.get = (key) =>
12-
storage.getItemAsync(`${AV.applicationId}/${key}`)
13-
.then(cache => {
14-
try {
15-
cache = JSON.parse(cache);
16-
} catch (e) {
17-
return null;
18-
}
19-
if (cache) {
20-
const expired = cache.expiredAt && cache.expiredAt < Date.now();
21-
if (!expired) {
22-
return cache.value;
23-
}
24-
return remove(key).then(() => null);
25-
}
26-
return null;
27-
});
11+
const getCacheData = (cacheData, key) => {
12+
try {
13+
cacheData = JSON.parse(cacheData);
14+
} catch (e) {
15+
return null;
16+
}
17+
if (cacheData) {
18+
const expired = cacheData.expiredAt && cacheData.expiredAt < Date.now();
19+
if (!expired) {
20+
return cacheData.value;
21+
}
22+
return removeAsync(key).then(() => null);
23+
}
24+
return null;
25+
};
26+
27+
exports.getAsync = (key) => {
28+
key = `${AV.applicationId}/${key}`;
29+
return storage.getItemAsync(key)
30+
.then(cache => getCacheData(cache, key));
31+
};
2832

29-
exports.set = (key, value, ttl) => {
33+
exports.setAsync = (key, value, ttl) => {
3034
const cache = { value };
3135
if (typeof ttl === 'number') {
3236
cache.expiredAt = Date.now() + ttl;

src/request.js

Lines changed: 64 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,19 @@
66
const request = require('superagent');
77
const debug = require('debug')('request');
88
const md5 = require('md5');
9-
const Promise = require('./promise');
9+
const AVPromise = require('./promise');
1010
const Cache = require('./cache');
1111
const AVError = require('./error');
1212
const AV = require('./av');
13+
const _ = require('underscore');
14+
15+
const getServerURLPromise = new AVPromise();
16+
17+
// 服务器请求的节点 host
18+
const API_HOST = {
19+
cn: 'https://api.leancloud.cn',
20+
us: 'https://us-api.leancloud.cn',
21+
};
1322

1423
// 计算 X-LC-Sign 的签名方法
1524
const sign = (key, isMasterKey) => {
@@ -65,7 +74,7 @@ const checkRouter = (router) => {
6574
const ajax = (method, resourceUrl, data, headers = {}, onprogress) => {
6675
debug(method, resourceUrl, data, headers);
6776

68-
const promise = new Promise();
77+
const promise = new AVPromise();
6978
const req = request(method, resourceUrl)
7079
.set(headers)
7180
.send(data)
@@ -109,7 +118,7 @@ const setHeaders = (sessionToken) => {
109118
headers['User-Agent'] = AV._config.userAgent || `AV/${AV.version}; Node.js/${process.version}`;
110119
}
111120

112-
const promise = new Promise();
121+
const promise = new AVPromise();
113122

114123
// Pass the session token
115124
if (sessionToken) {
@@ -179,20 +188,23 @@ const cacheServerURL = (serverURL, ttl) => {
179188
if (typeof ttl !== 'number') {
180189
ttl = 3600;
181190
}
182-
Cache.set('APIServerURL', serverURL, ttl * 1000);
191+
return Cache.setAsync('APIServerURL', serverURL, ttl * 1000);
183192
};
184193

185194
// handle AV._request Error
186195
const handleError = (res) => {
187-
const promise = new Promise();
196+
const promise = new AVPromise();
188197
/**
189198
When API request need to redirect to the right location,
190199
can't use browser redirect by http status 307, as the reason of CORS,
191200
so API server response http status 410 and the param "location" for this case.
192201
*/
193202
if (res.statusCode === 410) {
194-
cacheServerURL(res.response.api_server, res.response.ttl);
195-
promise.resolve(res.response.location);
203+
cacheServerURL(res.response.api_server, res.response.ttl).then(() => {
204+
promise.resolve(res.response.location);
205+
}).catch((error) => {
206+
promise.reject(error);
207+
});
196208
} else {
197209
let errorJSON = { code: -1, error: res.responseText };
198210
if (res.response && res.response.code) {
@@ -213,40 +225,44 @@ const handleError = (res) => {
213225
return promise;
214226
};
215227

216-
const setServerUrlByRegion = (region = 'cn') => {
217-
// 服务器请求的节点 host
218-
const API_HOST = {
219-
cn: 'https://api.leancloud.cn',
220-
us: 'https://us-api.leancloud.cn',
221-
};
228+
const setServerUrl = (serverURL) => {
229+
AV._config.APIServerURL = `https://${serverURL}`;
222230

223-
const AVConfig = AV._config;
224-
AVConfig.region = region;
231+
// 根据新 URL 重新设置区域
232+
const newRegion = _.findKey(API_HOST, item => item === AV._config.APIServerURL);
233+
if (newRegion) {
234+
AV._config.region = newRegion;
235+
}
236+
};
237+
238+
const refreshServerUrl = () => {
239+
const url = `https://app-router.leancloud.cn/1/route?appId=${AV.applicationId}`;
240+
return ajax('get', url).then(servers => {
241+
if (servers.api_server) {
242+
setServerUrl(servers.api_server);
243+
return cacheServerURL(servers.api_server, servers.ttl);
244+
}
245+
});
246+
};
247+
248+
const setServerUrlByRegion = (region = 'cn') => {
225249
// 如果用户在 init 之前设置了 APIServerURL,则跳过请求 router
226-
if (AVConfig.APIServerURL) {
250+
if (AV._config.APIServerURL) {
227251
return;
228252
}
229-
AVConfig.APIServerURL = API_HOST[region];
230-
if (region === 'cn') {
231-
Cache.get('APIServerURL').then(cachedServerURL => {
232-
if (cachedServerURL) {
233-
return cachedServerURL;
234-
} else {
235-
return ajax('get', `https://app-router.leancloud.cn/1/route?appId=${AV.applicationId}`)
236-
.then(servers => {
237-
if (servers.api_server) {
238-
cacheServerURL(servers.api_server, servers.ttl);
239-
return servers.api_server;
240-
}
241-
});
242-
}
243-
}).then(serverURL => {
244-
// 如果用户在 init 之后设置了 APIServerURL,保持用户设置
245-
if (AVConfig.APIServerURL === API_HOST[region]) {
246-
AVConfig.APIServerURL = `https://${serverURL}`;
247-
}
248-
});
249-
}
253+
AV._config.region = region;
254+
AV._config.APIServerURL = API_HOST[region];
255+
256+
Cache.getAsync('APIServerURL').then((serverURL) => {
257+
if (serverURL) {
258+
setServerUrl(serverURL);
259+
getServerURLPromise.resolve();
260+
} else {
261+
refreshServerUrl().then(() => {
262+
getServerURLPromise.resolve();
263+
});
264+
}
265+
});
250266
};
251267

252268
/**
@@ -266,16 +282,18 @@ const AVRequest = (route, className, objectId, method, dataObject = {}, sessionT
266282
}
267283

268284
checkRouter(route);
269-
const apiURL = createApiUrl(route, className, objectId, method, dataObject);
270285

271-
return setHeaders(sessionToken).then(
272-
headers => ajax(method, apiURL, dataObject, headers)
273-
.then(
274-
null,
275-
res => handleError(res)
276-
.then(location => ajax(method, location, dataObject, headers))
277-
)
278-
);
286+
return getServerURLPromise.always(() => {
287+
const apiURL = createApiUrl(route, className, objectId, method, dataObject);
288+
return setHeaders(sessionToken).then(
289+
headers => ajax(method, apiURL, dataObject, headers)
290+
.then(
291+
null,
292+
res => handleError(res)
293+
.then(location => ajax(method, location, dataObject, headers))
294+
)
295+
);
296+
});
279297
};
280298

281299
module.exports = {

src/utils.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,9 @@ const init = (AV) => {
159159
// 兼容旧版本的初始化方法
160160
case 2:
161161
case 3:
162-
console.warn('Please use AV.init() to replace AV.initialize() .');
162+
console.warn('Please use AV.init() to replace AV.initialize(), ' +
163+
'AV.init() need an Object param, like { appId: \'YOUR_APP_ID\', appKey: \'YOUR_APP_KEY\' } . ' +
164+
'Docs: https://leancloud.cn/docs/sdk_setup-js.html');
163165
if (!AVConfig.isNode && args.length === 3) {
164166
masterKeyWarn();
165167
}

test/cache.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,14 @@ var wait = function wait(time) {
55
});
66
};
77

8-
describe('Cache', function () {
8+
describe('Cache async', function () {
99
var getValue = function getValue() {
10-
return Cache.get('__test');
10+
return Cache.getAsync('__test');
1111
};
12-
it('get/set', function () {
13-
return Cache.set('__test', 1).then(getValue).then(function (value) {
12+
it('get/set async', function () {
13+
return Cache.setAsync('__test', 1).then(getValue).then(function (value) {
1414
expect(value).to.be(1);
15-
return Cache.set('__test', '1', 100).then(getValue);
15+
return Cache.setAsync('__test', '1', 100).then(getValue);
1616
}).then(function (value) {
1717
expect(value).to.be('1');
1818
return wait(110).then(getValue);

0 commit comments

Comments
 (0)