Skip to content

Commit fc74002

Browse files
committed
Merge pull request #271 from leeyeh/feat-app-router
feat: app router
2 parents 4f52349 + 7eda09b commit fc74002

File tree

11 files changed

+156
-124
lines changed

11 files changed

+156
-124
lines changed

.editorconfig

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
root = true
2+
3+
[*]
4+
indent_style = space
5+
indent_size = 2
6+
end_of_line = lf
7+
insert_final_newline = true

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
language: node_js
22

33
node_js:
4-
- "4.2"
4+
- "4"
55
- "0.12"
66

77
sudo: false

demo/index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,6 @@ <h2><a href="https://leancloud.cn">为开发加速</a></h2>
1111
<p>欢迎调试 JavaScript SDK,请打开浏览器控制台</p>
1212
</div>
1313
<script src="../dist/av.js"></script>
14-
<script src="../test-es5.js"></script>
14+
<script src="./test-es5.js"></script>
1515
</body>
1616
</html>

gulpfile.babel.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -255,4 +255,3 @@ gulp.task('dev', [
255255
'babel-demo'
256256
]).on('change', reload);
257257
});
258-

src/av.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ AV._ = require('underscore');
1919
AV.version = require('./version');
2020
AV.Promise = require('./promise');
2121
AV.localStorage = require('./localstorage');
22+
AV.Cache = require('./cache');
2223

2324
// 挂载所有内部配置项
2425
AV._config = AV._config || {};

src/browserify-wrapper/ajax-browser.js

Lines changed: 6 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -6,31 +6,12 @@
66
'use strict';
77

88
const AVPromise = require('../promise');
9-
const md5 = require('md5');
9+
const debug = require('debug')('ajax');
1010

11-
// 计算 X-LC-Sign 的签名方法
12-
const sign = (key, isMasterKey) => {
13-
const now = new Date().getTime();
14-
const signature = md5(now + key);
15-
if (isMasterKey) {
16-
return signature + ',' + now + ',master';
17-
} else {
18-
return signature + ',' + now;
19-
}
20-
};
21-
22-
const ajax = (method, url, data, success, error) => {
23-
const AV = global.AV;
11+
const ajax = (method, url, data, headers = {}) => {
12+
debug(method, url, data, headers);
2413

2514
const promise = new AVPromise();
26-
const options = {
27-
success: success,
28-
error: error
29-
};
30-
31-
const appId = AV.applicationId;
32-
const appKey = AV.applicationKey;
33-
const masterKey = AV.masterKey;
3415

3516
let handled = false;
3617
const xhr = new global.XMLHttpRequest();
@@ -41,6 +22,8 @@ const ajax = (method, url, data, success, error) => {
4122
}
4223
handled = true;
4324

25+
debug(xhr.status, xhr.responseText);
26+
4427
if (xhr.status >= 200 && xhr.status < 300) {
4528
let response;
4629
try {
@@ -59,59 +42,14 @@ const ajax = (method, url, data, success, error) => {
5942
}
6043
};
6144

62-
let headers = {
63-
'X-LC-Id': appId,
64-
'X-LC-UA': 'LC-Web-' + AV.version,
65-
'Content-Type': 'application/json;charset=UTF-8'
66-
};
67-
68-
// 清理原来多余的数据(如果不清理,会污染数据表)
69-
if (data) {
70-
delete data._ApplicationId;
71-
delete data._ApplicationKey;
72-
delete data._ApplicationProduction;
73-
delete data._MasterKey;
74-
delete data._ClientVersion;
75-
delete data._InstallationId;
76-
77-
if (data._SessionToken) {
78-
headers['X-LC-Session'] = data._SessionToken;
79-
delete data._SessionToken;
80-
}
81-
}
82-
83-
if (method.toLowerCase() === 'get') {
84-
let i = 0;
85-
for (let k in data) {
86-
if (i === 0) {
87-
url = url + '?';
88-
} else {
89-
url = url + '&';
90-
}
91-
92-
if (typeof data[k] === 'object') {
93-
data[k] = JSON.stringify(data[k]);
94-
}
95-
96-
url = url + k + '=' + encodeURIComponent(data[k]);
97-
i ++;
98-
}
99-
}
100-
101-
if (masterKey && AV._useMasterKey) {
102-
headers['X-LC-Sign'] = sign(masterKey, true);
103-
} else {
104-
headers['X-LC-Sign'] = sign(appKey);
105-
}
106-
10745
xhr.open(method, url, true);
10846

10947
for (let name in headers) {
11048
xhr.setRequestHeader(name, headers[name]);
11149
}
11250

11351
xhr.send(JSON.stringify(data));
114-
return promise._thenRunCallbacks(options);
52+
return promise;
11553
};
11654

11755
module.exports = ajax;

src/browserify-wrapper/ajax.js

Lines changed: 10 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -8,44 +8,33 @@
88
const http = require('http');
99
const https = require('https');
1010
const url = require('url');
11+
const debug = require('debug')('ajax');
1112

1213
const Promise = require('../promise');
1314
const VERSION = require('../version');
1415

15-
// `keepAlive` option only work on Node.js 0.12+
16-
var httpAgent = new http.Agent({keepAlive: true});
17-
var httpsAgent = new https.Agent({keepAlive: true});
18-
19-
module.exports = function _ajax(method, resourceUrl, data, success, error) {
20-
if (method.toLowerCase() !== 'post') {
21-
data = data || {};
22-
data._method = method;
23-
method = 'post';
24-
}
25-
data = JSON.stringify(data);
16+
module.exports = function _ajax(method, resourceUrl, data, headers = {}) {
17+
debug(method, resourceUrl, data, headers);
2618

2719
var parsedUrl = url.parse(resourceUrl);
20+
2821
var promise = new Promise();
2922

3023
var transportModule = http;
31-
var transportAgent = httpAgent;
3224

3325
if (parsedUrl.protocol === 'https:') {
3426
transportModule = https;
35-
transportAgent = httpsAgent;
3627
}
3728

29+
delete headers['X-LC-UA'];
30+
headers['User-Agent'] = _ajax.userAgent || 'AV/' + VERSION + '; Node.js/' + process.version;
3831
var req = transportModule.request({
3932
method: method,
4033
protocol: parsedUrl.protocol,
4134
hostname: parsedUrl.hostname,
4235
port: parsedUrl.port,
4336
path: parsedUrl.path,
44-
agent: transportAgent,
45-
headers: {
46-
'Content-Type': 'text/plain',
47-
'User-Agent': _ajax.userAgent || 'AV/' + VERSION + '; Node.js/' + process.version
48-
}
37+
headers,
4938
});
5039

5140
req.on('response', function(res) {
@@ -56,6 +45,7 @@ module.exports = function _ajax(method, resourceUrl, data, success, error) {
5645
});
5746

5847
res.on('end', function() {
48+
debug(res.statusCode, responseText);
5949
if (res.statusCode >= 200 && res.statusCode < 300) {
6050
try {
6151
promise.resolve(JSON.parse(responseText), res.statusCode, res);
@@ -74,9 +64,6 @@ module.exports = function _ajax(method, resourceUrl, data, success, error) {
7464
promise.reject(err);
7565
});
7666

77-
req.end(data);
78-
return promise._thenRunCallbacks({
79-
success: success,
80-
error: error
81-
});
67+
req.end(JSON.stringify(data));
68+
return promise;
8269
};

src/cache.js

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
'use strict';
2+
const storage = require('./localstorage');
3+
const AV = require('./av');
4+
5+
const remove = exports.remove = storage.removeItemAsync.bind(storage);
6+
7+
exports.get = (key) => {
8+
return storage.getItemAsync(`${AV.applicationId}/${key}`)
9+
.then(cache => {
10+
try {
11+
cache = JSON.parse(cache);
12+
} catch (e) {
13+
return null;
14+
}
15+
if (cache) {
16+
const expired = cache.expiredAt && cache.expiredAt < Date.now();
17+
if (!expired) {
18+
return cache.value;
19+
}
20+
return remove(key).then(() => null);
21+
}
22+
return null;
23+
});
24+
};
25+
26+
exports.set = (key, value, ttl) => {
27+
const cache = {
28+
value
29+
};
30+
if (typeof ttl === 'number') {
31+
cache.expiredAt = Date.now() + ttl;
32+
}
33+
return storage.setItemAsync(
34+
`${AV.applicationId}/${key}`,
35+
JSON.stringify(cache)
36+
);
37+
};

src/utils.js

Lines changed: 69 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,20 @@
77

88
const _ = require('underscore');
99
const ajax = require('./browserify-wrapper/ajax');
10+
const Cache = require('./cache');
11+
const md5 = require('md5');
12+
const debug = require('debug')('utils');
13+
14+
// 计算 X-LC-Sign 的签名方法
15+
const sign = (key, isMasterKey) => {
16+
const now = new Date().getTime();
17+
const signature = md5(now + key);
18+
if (isMasterKey) {
19+
return signature + ',' + now + ',master';
20+
} else {
21+
return signature + ',' + now;
22+
}
23+
};
1024

1125
const init = (AV) => {
1226

@@ -115,18 +129,35 @@ const init = (AV) => {
115129
AV._useMasterKey = false;
116130
};
117131

118-
const setRegionServer = (region) => {
119-
// 服务器地区选项,默认为中国大陆
120-
switch (region) {
121-
case 'us':
122-
AVConfig.region = 'us';
123-
break;
124-
default:
125-
AVConfig.region = 'cn';
126-
break;
127-
}
128-
if (!AVConfig.APIServerURL) {
129-
AVConfig.APIServerURL = API_HOST[AVConfig.region];
132+
const setRegionServer = (region = 'cn') => {
133+
AVConfig.region = region;
134+
// 如果用户在 init 之前设置了 APIServerURL,则跳过请求 router
135+
if (AVConfig.APIServerURL) {
136+
return;
137+
}
138+
AVConfig.APIServerURL = API_HOST[region];
139+
if (region === 'cn') {
140+
Cache.get('APIServerURL').then(cachedServerURL => {
141+
if (cachedServerURL) {
142+
return cachedServerURL;
143+
} else {
144+
return ajax('get', `https://app-router.leancloud.cn/1/route?appId=${AV.applicationId}`)
145+
.then(servers => {
146+
if (servers.api_server) {
147+
Cache.set(
148+
'APIServerURL',
149+
servers.api_server,
150+
(typeof servers.ttl ==='number' ? servers.ttl : 3600) * 1000);
151+
return servers.api_server;
152+
}
153+
});
154+
}
155+
}).then(serverURL => {
156+
// 如果用户在 init 之后设置了 APIServerURL,保持用户设置
157+
if (AVConfig.APIServerURL === API_HOST[region]) {
158+
AVConfig.APIServerURL = `https://${serverURL}`;
159+
}
160+
})
130161
}
131162
};
132163

@@ -390,36 +421,44 @@ const init = (AV) => {
390421
}
391422
}
392423

393-
dataObject = _.clone(dataObject || {});
394-
dataObject._ApplicationId = AV.applicationId;
395-
dataObject._ApplicationKey = AV.applicationKey;
396-
if (!AV._isNullOrUndefined(AV.applicationProduction)) {
397-
dataObject._ApplicationProduction = AV.applicationProduction;
424+
if (method.toLowerCase() === 'get') {
425+
if (apiURL.indexOf('?') === -1) {
426+
apiURL += '?';
427+
}
428+
for (let k in dataObject) {
429+
if (typeof dataObject[k] === 'object') {
430+
dataObject[k] = JSON.stringify(dataObject[k]);
431+
}
432+
apiURL += '&' + k + '=' + encodeURIComponent(dataObject[k]);
433+
}
434+
}
435+
436+
var headers = {
437+
'X-LC-Id': AV.applicationId,
438+
'X-LC-UA': 'LC-Web-' + AV.version,
439+
'Content-Type': 'application/json;charset=UTF-8'
440+
};
441+
if (AV.masterKey && AV._useMasterKey) {
442+
headers['X-LC-Sign'] = sign(AV.masterKey, true);
443+
} else {
444+
headers['X-LC-Sign'] = sign(AV.applicationKey);
398445
}
399-
if (AV._useMasterKey) {
400-
dataObject._MasterKey = AV.masterKey;
446+
if (!AV._isNullOrUndefined(AV.applicationProduction)) {
447+
headers['X-LC-Prod'] = AV.applicationProduction;
401448
}
402-
dataObject._ClientVersion = AV.version;
403449
return AV.Promise.as().then(function() {
404450
// Pass the session token
405451
if (sessionToken) {
406-
dataObject._SessionToken = sessionToken;
452+
headers['X-LC-Session'] = sessionToken;
407453
} else if (!AV._config.disableCurrentUser) {
408454
return AV.User.currentAsync().then(function(currentUser) {
409455
if (currentUser && currentUser._sessionToken) {
410-
dataObject._SessionToken = currentUser._sessionToken;
456+
headers['X-LC-Session'] = currentUser._sessionToken;
411457
}
412458
});
413459
}
414460
}).then(function() {
415-
// Pass the installation id
416-
if (!AV._config.disableCurrentUser) {
417-
return AV._getInstallationId().then(function(installationId) {
418-
dataObject._InstallationId = installationId;
419-
});
420-
}
421-
}).then(function() {
422-
return AV._ajax(method, apiURL, dataObject).then(null, function(response) {
461+
return AV._ajax(method, apiURL, dataObject, headers).then(null, function(response) {
423462
// Transform the error into an instance of AV.Error by trying to parse
424463
// the error string as JSON.
425464
var error;

0 commit comments

Comments
 (0)