0

我正在使用 Appcelerator Titanium 编写一个移动应用程序,它会发出很多不同的 xhr 请求。这不是真正的 Appcelerator Titanium 特定问题。但是,如果您确实编写了一些代码,我希望它是 javascript。

应用程序需要对自身进行身份验证,用户必须为某些交互记录等。

我已经到了任何请求都可能得到任何类型的响应的地步,例如:

  • 未认证
  • 未登录
  • 坏参数
  • 成功的
  • ...

请求被包装在不同的模型方法或助手中。

问题是,我不熟悉这种应用程序。我想知道什么是最佳实践。

例如,一些真正的问题是:

  • 如果应用程序未通过身份验证(令牌已过期,首次启动),应用程序是否应尝试对其自身进行身份验证,然后再次发送被拒绝的请求?(对用户透明)

  • 我是否应该在每次应用启动时发送身份验证请求然后“忘记”它?

我面临的问题是,如果我尝试为每个请求处理这个代码,代码会很快变大。充满了嵌套的回调,重试条件,各种事件监听器来管理等等。只是感觉不是很“好”。而且它根本不是 DRY,当我真正需要的是任何请求时,检查有什么问题,尝试修复它(如果没有,则进行身份验证,如果可能,自动登录或显示登录 UI 等。)然后如果可行,重试原始请求几次,如果需要中止。

我一直在研究承诺模式,但只知道理论,不知道它是否是我需要的。

所以我欢迎任何关于这个特定问题的建议。我想知道像“Facebook”这样的应用程序是如何处理这个问题的。

感谢您的帮助

4

1 回答 1

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));
                        }
});

请注意,这并不完整,并且不检查连接性,没有真正的错误处理等,但它可能会帮助您了解。

我想这里有很多东西要谈,但我现在就停在这里……

于 2013-09-11T12:06:44.730 回答