来自swift的JSON请求在php中显示空数组

Posted

技术标签:

【中文标题】来自swift的JSON请求在php中显示空数组【英文标题】:JSON request from swift showing empty array in php 【发布时间】:2019-12-13 20:07:17 【问题描述】:

我正在尝试从我的 swift 应用程序向 php 服务器发出请求。由于某种原因,php 将一个空数组显示为 $_REQUEST 变量。我已经查看了堆栈溢出并实现了我能找到的所有可能有帮助的东西,但仍然在 php.ini 中得到一个空数组。这是相关的swift代码...

func connect(_ pin: String, completion: @escaping(Result<ConnectResponse?, Error>) -> ()) 
  let params: [String : Any] = [
    "mobile_pin_connect": pin,
    "device_info": UIDevice().model,
    "additional_info": UIDevice().systemVersion
  ]
  doRequest(params: params)  (data) in
    if let data = data 
      do 
        let res = try JSONDecoder().decode(Dictionary<String, String>.self, from: data)
        completion(.success(
          ConnectResponse(success: (res["success"] == "true"), connect_id: res["connect_id"] ?? nil, error: res["error"] ?? nil)))
       catch 
        completion(.failure(error))
      
     else 
      print("in else block")
    
  


fileprivate func doRequest(params: [String: Any], completion: @escaping (Data?) -> ()) 
        let body = createJsonBody(params)!
        self.request.httpBody = body
        print("Sending request with thw following variables")
        print(String(data: body, encoding: .utf8)!)
        print(String(data: self.request.httpBody!, encoding: .utf8))
        URLSession.shared.dataTask(with: self.request)  (data, response, error) in
            if let error = error 
                print("Error in request: \(error)")
                completion(nil)
            
            let stringResult = String(data: data!, encoding: .utf8)!
            let properResult = String(stringResult.map 
                $0 == "." ? "=" : $0
            )
            let decodedData = Data(base64Encoded: properResult)
            completion(decodedData)
        .resume()
    

fileprivate func createJsonBody(_ params: [String: Any]) -> Data? 
        do 
            let jsonData = try JSONSerialization.data(withJSONObject: params)
            let body = Data(jsonData).base64EncodedData()
            return body
         catch 
            print("Unable to create json body: " + error.localizedDescription, error)
            return nil
        
    

将请求发送到服务器,请求的设置在静态变量设置中...

private static var sharedConnector: ApiConnector = 
        let url = URL(string: "https://mywebsiteURLhere.com/api/mobile/challenge")
        var request = URLRequest(url: url!)
        request.httpMethod = "POST"
        request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
        let connector = ApiConnector(request)
        return connector
    ()

所以我为 application/json 设置了正确的标头值,我设置了要发布的请求方法,我正在对 json 数据进行 base64 编码,并且在 PHP 中我设置了 php://input...

$rawRequest = file_get_contents("php://input");

并将 $_REQUEST 变量转储到错误日志中,但我总是得到数组\n(\n)\n 它只是显示一个空数组 我什至做到了

error_log("Raw request from index.php");
error_log(print_r($rawRequest, true));

它记录了一个完全空的行。 从我在网上看到的所有内容中,我无法弄清楚为什么 PHP 在请求中什么也没得到,我正在迅速正确地执行请求。非常感谢任何帮助。谢谢

【问题讨论】:

error_log(print_r($rawRequest, true)); 不等于 error_log(print_r($_REQUEST)); 首先,即使您成功发送了 JSON,$_REQUEST 也会为空。无论如何,小代码片段无助于解决您的问题。显示 PHP 和 Swift 的可构建和可执行代码。问题可能隐藏在隐藏的部分。 【参考方案1】:

根据您的 Swift 代码,能否请您替换以下方法。

fileprivate func createJsonBody(_ params: [String: Any]) -> Data? 
        do 

            let jsonData = try JSONSerialization.data(withJSONObject: params)
            let body = Data(jsonData)
            return body
         catch 
            print("Unable to create json body: " + error.localizedDescription, error)
            return nil
        
    

您需要将这一行 let body = Data(jsonData) 替换为 let body = Data(jsonData).base64EncodedData()

【讨论】:

【参考方案2】:

没有看到你的 PHP 代码,很难确定整个画面。但是,无论您执行什么步骤通过客户端 (Swift) 对数据进行编码,您都必须反转才能成功解码服务器上的消息。

例如,如果您准备并发送来自客户的请求,如下所示。

客户:

    JSON 编码数据 base-64 编码 发送数据

您的服务器必须反转步骤才能成功解码数据。

服务器:

    接收数据 base-64 解码数据 JSON 解码数据

除非您的服务器需要,否则我会删除 base-64 编码步骤,因为它只会使您的编码/解码过程复杂化。

我创建了一个工作示例:https://github.com/stuartcarnie/***/tree/master/q59329179

克隆它或在你自己的项目中拉下特定代码。

要测试,打开终端并运行 php 服务器:

$ cd q59329179/php
$ php -S localhost:8080 router.php

PHP 7.3.9 Development Server started at Thu Dec 19 10:47:58 2019
Listening on http://localhost:8080
Document root is /Users/stuartcarnie/projects/***/q59329179/php
Press Ctrl-C to quit.

在另一个终端会话中测试它是否适用于 curl:

$ curl -XPOST localhost:8080 --data-binary '"string": "foo", "number": 5'

请注意,您应该在 php 会话中看到输出:

[Thu Dec 19 11:33:43 2019] Array
(
    [string] => foo
    [number] => 5
)

运行 Swift 测试:

$ cd q59329179/swift
$ swift run request

再次注意,php会话中的解码输出:

[Thu Dec 19 11:20:49 2019] Array
(
    [string] => string value
    [number] => 12345
    [bool] =>
)

【讨论】:

【参考方案3】:

您的请求可能没有通过 POST 结构到达,而是保存在请求正文中。

尝试将其作为您的第一个 PHP 操作运行:

$raw = file_get_contents('php://input');

看看现在$raw 中有什么(如果有的话)。你应该在那里看到一个 Base64 编码的字符串,你需要解码 - 像这样,如果你需要一个数组:

$info = json_decode(base64_decode($raw), true);

【讨论】:

【参考方案4】:

我已经测试了您的代码,它运行良好。问题可能出在您的 PHP 端。我已经在本地服务器以及httpbin

上测试了以下代码

来自本地服务器的输出(最新版本的 XAMPP (php 7.3.12)):

Sending request with thw following variables
eyJhZGRpdGlvbmFsX2luZm8iOiIxMy4yLjIiLCJtb2JpbGVfcGluX2Nvbm5lY3QiOiIxMjM0IiwiZGV2aWNlX2luZm8iOiJpUGhvbmUifQ==
result eyJhZGRpdGlvbmFsX2luZm8iOiIxMy4yLjIiLCJtb2JpbGVfcGluX2Nvbm5lY3QiOiIxMjM0IiwiZGV2aWNlX2luZm8iOiJpUGhvbmUifQ==
message ["additional_info": "13.2.2", "mobile_pin_connect": "1234", "device_info": "iPhone"]

代码:

ApiConnector.swift

import Foundation
import UIKit
class ApiConnector
    var request: URLRequest
   private init(request: URLRequest) 
        self.request = request
    

    public static var sharedConnector: ApiConnector = 
        let url = URL(string: "http://localhost/post/index.php")
        var request = URLRequest(url: url!)
        request.httpMethod = "POST"
        request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
        let connector = ApiConnector(request: request)
        return connector
    ()

    func connect(_ pin: String, completion: @escaping(Result<Dictionary<String, String>, Error>) -> ()) 
        let params: [String : Any] = [
            "mobile_pin_connect": pin,
            "device_info": UIDevice().model,
            "additional_info": UIDevice().systemVersion
        ]
        doRequest(params: params)  (data) in
            if let data = data 
                do 
                    let res = try JSONDecoder().decode(Dictionary<String, String>.self, from: data)
                    completion(.success(res))
                 catch 
                    completion(.failure(error))
                
             else 
                print("in else block")
            
        
    

    fileprivate func doRequest(params: [String: Any], completion: @escaping (Data?) -> ()) 
        let body = createJsonBody(params)!
        self.request.httpBody = body
        print("Sending request with thw following variables")
        print(String(data: body, encoding: .utf8)!)
        URLSession.shared.dataTask(with: self.request)  (data, response, error) in
            if let error = error 
                print("Error in request: \(error)")
                completion(nil)
            
            let stringResult = String(data: data!, encoding: .utf8)!
            print("result \(stringResult)")
            let properResult = String(stringResult.map 
                $0 == "." ? "=" : $0
            )
            let decodedData = Data(base64Encoded: properResult)
            completion(decodedData)
        .resume()
    

    fileprivate func createJsonBody(_ params: [String: Any]) -> Data? 
        do 
            let jsonData = try JSONSerialization.data(withJSONObject: params)
            let body = Data(jsonData).base64EncodedData()
            return body
         catch 
            print("Unable to create json body: " + error.localizedDescription, error)
            return nil
        
    

ViewController.swift

import UIKit
class ViewController: UIViewController 
 let session = URLSession.shared
    override func viewDidLoad() 
        super.viewDidLoad()

        ApiConnector.sharedConnector.connect("1234")  (result) in
            switch result 
            case .success(let message):
                print("message \(message)")
            case .failure(let error):
                print(error.localizedDescription)
            
        
    

index.php

echo file_get_contents("php://input");

您可以通过向https://httpbin.org/post发出请求来验证您的代码

输出:

Sending request with thw following variables
eyJkZXZpY2VfaW5mbyI6ImlQaG9uZSIsImFkZGl0aW9uYWxfaW5mbyI6IjEzLjIuMiIsIm1vYmlsZV9waW5fY29ubmVjdCI6IjEyMzQifQ==
result 
  "args": , 
  "data": "eyJkZXZpY2VfaW5mbyI6ImlQaG9uZSIsImFkZGl0aW9uYWxfaW5mbyI6IjEzLjIuMiIsIm1vYmlsZV9waW5fY29ubmVjdCI6IjEyMzQifQ==", 
  "files": , 
  "form": , 
  "headers": 
    "Accept": "*/*", 
    "Accept-Encoding": "gzip, deflate", 
    "Accept-Language": "en-us", 
    "Content-Length": "108", 
    "Content-Type": "application/json; charset=utf-8", 
    "Host": "httpbin.org", 
    "User-Agent": "SessionTest/1 CFNetwork/1120 Darwin/19.0.0"
  , 
  "json": null, 
  "origin": "122.173.135.243, 122.173.135.243", 
  "url": "https://httpbin.org/post"


in else block

如果您运行的是旧版本的 PHP,那么您可能需要 HTTP_RAW_POST_DATA

查看SO 以了解有关 PHP 方面的更多信息。

【讨论】:

以上是关于来自swift的JSON请求在php中显示空数组的主要内容,如果未能解决你的问题,请参考以下文章

如何通过 JSON 将数组从 php 解压到 Swift

在 PHP 中使用来自 AJAX 请求的 JSON 字符串 [关闭]

在 Swift iOS 中解码的 PHP JSON 返回空值

Swift - JSON解码返回空数组

来自网络请求 JSON 的 Swift 字符串有换行符 - 如何删除换行符?

无法在我的 collectionView 中显示来自数组(JSON)的数据