【问题标题】:JSON request from swift showing empty array in php来自swift的JSON请求在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 的可构建和可执行代码。问题可能隐藏在隐藏的部分。

标签: php json swift urlrequest


【解决方案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) 对数据进行编码,您都必须反转才能成功解码服务器上的消息。

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

    客户:

    1. JSON 编码数据
    2. base-64 编码
    3. 发送数据

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

    服务器:

    1. 接收数据
    2. base-64 解码数据
    3. JSON 解码数据

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

    我创建了一个工作示例:https://github.com/stuartcarnie/stackoverflow/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/stackoverflow/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 方面的更多信息。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2016-06-06
          • 1970-01-01
          • 2021-08-24
          • 2022-06-22
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多