2016年3月23日 星期三

原來參數可以這樣傳

跟另一家公司合作去競投項目,需要開發一個簡單的示範程式。我負責手機部份,對方負責服務器接口。

為了爭取時間盡快完成,可以拿去跟潛在客戶展示。我跟對方的編程同事夾了相關接口需要的參數,以及傳回的內容。格式用方便的 JSON。程式編好後,接口也到着,可是放在一起後發現無法連接。我對網絡方面的知識不多,看到網址的格式是「https://www.sitachan.com:310/」感到有點其怪。我認識的 HTTPS 是會導入到 443 埠,若地址帶有 310 埠,最終會是 443 還是 310 呢?如果是 443 則沒有懸念,若是 310 的話,數據會否被 SSL 加密呢?時間有限,我沒有深究。反正只是示範,日後再作跟進。對方改為 HTTP 搞掂。

之後引伸出另一個問題。無論我怎樣依照參數名稱及格式,都無法傳回內容。這裡也有一個奇怪點:參數也是 JSON 格式。
var parameter = JSON.stringify({
    "login":{
        "uuid":"A0B1C2D3E4F5G6H7",
        "timeStamp":"2016-03-23 12:34:56",
        "deviceType":"iPhone SE"
    }
});

$.ajax({url:"https://www.sitachan.com:310/",
    type: "POST",
    data: parameter,
    success: function(responseData)  {
        console.log(responseData);
    },
    error: function(request, status, error)  {
        console.log(request.responseText+": "+error);
    }
});
於是我編寫了一個 PHP 程式以相同參數、相同格式去讀取數值,用來確定手機程式沒有出錯。結果在我方的服務器運行得很順利;但一傳給對方的服務器卻讀不出任何數據...。讓我相信問題出在這裡,於是向對方索取他在服務器端讀取參數的代碼:
$json = json_decode(file_get_contents("php://input"), true);
很奇怪。我接觸到的不是 $_GET["login"]、$_POST["login"] 就提 $_REQUEST["login"],沒見過是 file_get_contents("php://input")。難怪 PHP 會讀不進任何東西、難怪對方說參數沒有名稱,不是「Key - Value」的方式...。有趣!

搞清楚後,焦點返回示範程式向服務器的請求方法。於是修改 PHP 程式來測試手機是否傳回對方能讀到的內容:
//========================================================================================
$jsonString = file_get_contents("php://input");
$json = json_decode($jsonString, true);
echo("{}");
error_log("jsonString: $jsonString");

foreach (getallheaders() as $name => $value) {
    error_log("$name: $value");
}
示範程式在 iPhone 上執行,用 AFNetworking 來連接服務器。可是怎麼搞都必須是「Key - Value」配對方式。反覆測試後,發現需要用「AFHTTPSessionManager」而不是用開的「AFHTTPRequestOperationManager」:
NSString *urlString = @"https://www.sitachan.com:310/";
NSDictionary *parameterDictionary = @{@"login":[NSDictionary dictionary]};

//--------------------------------------------------------------------------------------------------
//  Send it out to server
AFHTTPSessionManager *manager = [[AFHTTPSessionManager alloc] init];
manager.requestSerializer = [AFJSONRequestSerializer serializer];
manager.responseSerializer = [AFHTTPResponseSerializer serializer];
[manager POST:urlString parameters:parameterDictionary success:^(NSURLSessionDataTask *task, id responseObject)  {
 
    //--------------------------------------------------------------------------------------------------
    //  Success
    NSString *jsonString = [[NSString alloc] initWithData:responseObject encoding:NSUTF8StringEncoding];
    PSLog(@"Response: %@ connection done!\n%@", APPMANAGER_API_QUEUESTATUS, jsonString);

    NSDictionary *dictionary = [NSJSONSerialization JSONObjectWithData:responseObject options:NSJSONReadingMutableContainers error:nil];

    NSMutableDictionary *itemDictionary = [[NSMutableDictionary alloc] init];
    NSArray *dataArray = [dictionary objectForKey:@"data"];
    for (NSDictionary *dataDictionary in dataArray)  {

        NSString *itemNumber = [dataDictionary objectForKey:@"item"];
        NSString *key = [itemNumber substringToIndex:3];

        [itemDictionary setObject:itemNumber forKey:key];
    }
    _itemDictionary = itemDictionary;

    _errorCount = 0;

    [[NSNotificationCenter defaultCenter] postNotificationName:@"loginDone" object:nil userInfo:nil];
}  failure:^(NSURLSessionDataTask *task, NSError *error)  {

    _errorCount++;

    //--------------------------------------------------------------------------------------------------
    //  Failed, but never mind the result, just for record
    PSLog(@"### %@ %@", urlString, [error localizedDescription]);
    NSDictionary *dictionary = [NSDictionary dictionaryWithObjectsAndKeys:error.localizedDescription, APPMANAGER_KEY_ERROR, nil];
    [[NSNotificationCenter defaultCenter] postNotificationName:@"connectionError" object:nil userInfo:dictionary];
}];
原來參數可以這樣傳,又上了一課!

沒有留言: