我正在编写一个Appcelerator Titanium的移动应用程序,它可以提供很多不同的xhr请求。这不是Appcelerator Titanium特有的问题。但如果你写了一些代码,我希望它是javascript。
应用程序需要进行身份验证,必须记录用户进行某些交互等等。
我已经到了任何请求可能得到任何响应的地步,例如:
请求包含在不同的模型方法或帮助程序中。
问题是,我对这种应用并不熟悉。我想知道最佳做法是什么。
例如,一些真正的问题是:
如果应用未经过身份验证(令牌已过期,首次启动),应用是否应尝试对自身进行身份验证,然后再次发送被拒绝的请求? (对用户透明)
我应该在每次应用启动时发送身份验证请求,然后“忘记”它吗?
我面临的问题是,如果我尝试为每个请求处理此问题,代码会变得很快。充满嵌套的回调,重试条件,各种事件监听器来管理等等。它只是感觉不是很“好”。并且它根本不是DRY,当我真正需要的是任何请求,检查出错了,尝试修复它(如果不是则进行身份验证,如果可能则自动登录或显示登录UI等等)然后如果可行则重试原始请求几次,如果需要就中止。
我一直在关注承诺模式,但只知道理论,不知道它是否是我需要的。
所以我欢迎任何关于这个特殊问题的建议。我想知道像“Facebook”这样的应用程序如何处理这个问题。
感谢您的帮助
答案 0 :(得分:1)
这个问题不容易回答,但让我试着给你一些想法:
最重要的是,在对应用程序中的任何内容进行编码之前,就是API本身。它必须可靠并符合标准。我不会在这里详细介绍,但编写良好的RESTful API可以显着降低httpClient的复杂性。它必须使用标准的http状态代码以及POST,GET,PUT,DELETE等方法进行响应。
George Reese写的The REST API Design Handbook非常好。
我对使用Titanium的httpClients的方法是一个单独的模块,在需要的地方通过require()加载。我一次只关注一个客户端,因为我遇到了多个并行调用的大量问题。无论何时进行呼叫,客户端都会检查是否已有正在进行的呼叫,并在必要时将其发送到队列。
让我举个例子。为简洁起见,我遗漏了很多东西:
// lib/customClient.js
var xhrRequest; // This will be our HTTPClient
var callQueue = []; // This will be our queue
// Register the request
// params are:
// method (e.g. 'GET')
// url (e.g. 'http://test.com/api/v1/user/1')
// done (callback function)
function registerRequest(params) {
if(!xhrRequest) {
sendRequest(params);
} else {
queueRequest(params);
}
}
// This simply sends the request
// to the callQueue
function queueRequest(params) {
callQueue.push(params);
}
// Send the request with the params from register
// Please note that I do not hardcode error messages,
// I just do it here so it is easier to read
function sendRequest(params) {
// Set callback if available and valid
var callback = params.done && typeof(params.done) === "function" ? params.callback : null;
// Set method
var method = params.method || 'GET';
// Create the HTTP Client
xhrRequest = Ti.Network.createHTTPClient({
// Success
onload: function() {
// You can check for status codes in detail here
// For brevity, I will just check if it is valid
if (this.status >= 200 && this.status < 300) {
if(this.responseText) {
// You might want to check if it can be parsed as JSON here
try {
var jsonData = JSON.parse(this.responseText);
if(callback) callback({ success: true, response: jsonData });
} catch(e) {
if(callback) callback({ success: false, errormessage: 'Could not parse JSON data' });
}
processQueue();
} else {
if(callback) callback({ success: false, errormessage: 'No valid response received' });
processQueue();
}
} else {
if(callback) callback({ success: false, errormessage: 'Call response is success but status is ' + this.status });
processQueue();
}
},
// Error
onerror: function(e) {
if(this.responseText) {
try {
var jsonData = JSON.parse(this.responseText);
if(callback) callback({ success: false, reponse: jsonData });
} catch(e) {};
}
processQueue();
},
});
// Prepare and send request
// A lot more can (and should) be configured here, check documentation!
xhrRequest.setTimeout(10000);
xhrRequest.open(method, params.url);
xhrRequest.send();
}
// Checks if there is anything else in the queue
// and sends it
function processQueue() {
xhrRequest = null;
var nextInQueue = callQueue.shift();
if(nextInQueue) sendRequest(nextInQueue);
}
// Our public API
var publicAPI = {
sendRequest: function(params) {
registerRequest(params);
}
};
module.exports = publicAPI;
然后我可以从任何其他控制器/视图发送呼叫
var customClient = require('lib/customClient'); // omit 'lib' if you use alloy
// Send the request
customClient.sendRequest({
method : 'GET',
url : 'http://test.com/api/v1/user/1',
done : function(response) {
Ti.API.debug(JSON.stringify(response));
}
});
请注意,这不是完整的,不检查连接性,没有真正的错误处理等,但它可能有助于您了解。
我认为这里有很多东西需要讨论,但我现在暂时停在这里......