将 Swift 与 URLSession 一起使用可用于 GET 和 PUT,但在我使用 POST 时会出现错误 405 Method Not Allowed

Using Swift with URLSession works with GET and PUT, but it gives error 405 Method Not Allowed when I use POST

我使用 Swift 开发了一个 iOS 应用程序。

我使用以下方法通过 PUT 方法访问登录端点。

    let loginData = LoginModel("myUser","myPassword")
    var loginClassJson:Data?
    do{
        loginClassJson =  try JSONEncoder().encode(loginData)
    } catch {
         fatalError("Unable To Convert in Json")
    }
            
    let completeUrl = URL(string: RESconstantes.URL_PRINCIPAL_TREINAGEDAVE + "/login" )!
    var request = URLRequest(url: completeUrl)
    
    let myConfig = URLSessionConfiguration.default
    let base64LoginString = EndpointController.getBase64StringLoginWithUserAndPasswordV2()
    myConfig.httpAdditionalHeaders = ["Authorization" : base64LoginString]
    
    request.httpMethod = "PUT"
    request.setValue("\(String(describing: loginClassJson!.count))", forHTTPHeaderField: "Content-Length")
    request.setValue("application/json", forHTTPHeaderField: "Content-Type")
    request.httpBody = loginClassJson
            
    let sessionDelegate = SessionDelegate()
    let urlSession = URLSession(configuration: myConfig, delegate: sessionDelegate, delegateQueue: OperationQueue.main)
    
    let task = urlSession.dataTask(with: request as URLRequest, completionHandler: {
        (data, response, error) in
        
        if let error = error{
            print("errorX: ")
            print(error)
            return
        }
        if let data = data{
            let returnData = String(data: data, encoding: String.Encoding.ascii)
            print("dataX: ")
            print(returnData)
        }
        if let response = response{
            print("responseX: ")
            print(response)
        }
        
    })
    task.resume()
    print("END")

这是我的 URLSessionDelegate class

class SessionDelegate:NSObject, URLSessionDelegate
{
    func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
    // usado para fazer o bypass na autenticação self-signed do certificado do servidor
    // We've got a URLAuthenticationChallenge - we simply trust the HTTPS server and we proceed
    print("start didReceive challenge 1")
    if true {
        print("didReceive challenge 2")
        completionHandler(.useCredential, URLCredential(trust: challenge.protectionSpace.serverTrust!))
    }else{
        completionHandler(.performDefaultHandling, nil)
    }
}

它非常适合我,但现在我尝试创建代码以使用 POST 方法

访问另一个端点
let resDadoModel = ResDadoModel.getResenhaById(1)
    let jsonRequestUploadResenha = ResDadoModel.createMockJsonObjectResenhaDados(resDadoModel)
    let json: [String: Any] = jsonRequestUploadResenha
    guard let jsonData:Data = try? JSONSerialization.data(withJSONObject: json) else {
        print("guard jsonData error")
        return
    }        
    let completeUrl = URL(string: RESconstantes.URL_PRINCIPAL_TREINAGEDAVE + "/validaResenha" )!
    var request = URLRequest(url: completeUrl)
    
    let myConfig = URLSessionConfiguration.default
    let base64LoginString = EndpointController.getBase64StringLoginWithUserAndPasswordV2()
    myConfig.httpAdditionalHeaders = ["Authorization" : base64LoginString, "Content-Type":""]
    
    request.httpMethod = "POST"
    request.setValue("\(String(describing: jsonData.count))", forHTTPHeaderField: "Content-Length")
    request.setValue("application/json", forHTTPHeaderField: "Content-Type")
    request.httpBody = jsonData
            
    let sessionDelegate = SessionDelegate()
    let urlSession = URLSession(configuration: myConfig, delegate: sessionDelegate, delegateQueue: OperationQueue.main)
    
    let task = urlSession.dataTask(with: request as URLRequest, completionHandler: {
        (data, response, error) in
        
        if let error = error{
            print("errorX: ")
            print(error)
            return
        }
        if let data = data{
            let returnData = String(data: data, encoding: String.Encoding.ascii)
            print("dataX: ")
            print(returnData)
        }
        if let response = response{
            print("responseX: ")
            print(response)
        }            
    })
    task.resume()
    print("END")

但是我用来访问名为“validaResenha”的端点的代码无法正常工作,我收到 405 方法不允许错误。

我得到以下响应数据

<NSHTTPURLResponse: 0x600002028560> { URL: https://my_url_endpoint/api/spservicos/v1/validaResenha } { Status Code: 405, Headers {
Allow =     (
    "POST, OPTIONS"
);
"Cache-Control" =     (
    "no-cache=\"set-cookie, set-cookie2\""
);
Connection =     (
    "Keep-Alive"
);
"Content-Language" =     (
    "en-US"
);
"Content-Length" =     (
    0
);
"Content-Type" =     (
    "text/plain"
);
Date =     (
    "Thu, 23 Dec 2021 23:16:21 GMT"
);
Expires =     (
    "Thu, 01 Dec 1994 16:00:00 GMT"
);
"Keep-Alive" =     (
    "timeout=10, max=100"
);
"Set-Cookie" =     (
    "LtpaToken2=L6DEf/sqCSjiI1rePW3wEWZo40oNAsxmNVBNTpIRm3FZZRSSgaqmUTDYdjTq2PNE4+FhiIOKw7Xzuta4+LpD3cUB8QKZQ/KVom/rFFQ50XNkpQezmgMlgsmDDgtodRxVU5eyo1P1NP6r/3M55eY4HkeD583kXQB3/+EH3dIryo0ii6Jn6PrxaspX5noEo0eSt+yF2AylLdU66fCcSMJw7LCrB8Tulna4xHe4Nb9i+O5z2mnTXoIgbozDGuXfS6Y20zPrsaN62Bx1X/nySf1luf1QMhrt6P4SPF6GVudm0s/Db9dS0b444kJA4kMSJ0NbZ2khMzV1zSg3eZY6xZg2kidV8Qczpe5bL2/DNrPQY/CrUo8wcdFE1ebfxDcVrjv3G+nH6uKOPWtbcHHx9Wp1gvHLxj3cJ5MP43AzxW/7GXPA7QlsmlquxW1Ck7OypsP2hrYCvCWubjGdM51cg8uqhIonI+uXRO6BlcXIsPOfpR+LbQfDNo+9vzXzB+CZKZmYnBX63ffWhX09Cr+Ua0a2Sw8mOcE5jXImlO49+ak0FHPkiiaSABzuOl6ALYg9J6LCxjm6MC9bKd7KbMPueJI/ugVeMyphQwss5AHxic8fVmo+7/XNRT6zr4I/01N8xFQsqrvx5+i2AhxWO1bdDKmpZQLPoTHMD7TPcFBkwDXLVqXPXkpkcGvg3mI8ssKOOlxwJT7/SETcqrCY5O8Yr505qdeZiNIj4kjKiLoLuNpE+ZI=; Path=/"
);
} }

有人知道为什么我收到不允许的 405 错误方法吗?如果我使用 POSTMAN,POST 方法对我有用。如果我将 PUT 或 GET 端点与 Swift 代码一起使用,它会起作用,但如果我尝试在 Swift.

中尝试将端点与 POST 方法一起使用,它就会失败

我看到了一些奇怪的东西,“Content-Type”在响应中定义为 text/plain,但我将其设置为“application/json”。我不明白为什么没有设置配置。

如果我通过 POSTMAN 调用它,它可以工作,但出于某种原因我不知道为什么当我使用 Swift.

时它不工作

--- 编辑 ---

根据@matt 的建议,我使用 Postman 生成 Swift 代码。

我将 Swift 代码复制并粘贴到我的项目中,这是代码:

var semaphore = DispatchSemaphore (value: 0)

    let parameters = "{ \n    \"token\":\"MY_TOKEN\",\n    \"resenha\": {\n        \"codAP\":\"353750303020001\",\n        \"codPropriedade\":\"0\",\n        \"cpfVeterinario\":\"01787568814\",\n        \"coordGeoLat\": \"37.421565\",\n        \"coordGeoLong\": \"-122.084\",\n        \"cpfCnpjProdutor\": \"89058500810\",\n        \"dataNascimentoAnimal\": \"01/08/1981\",\n        \"fotos\": null,\n        \"graficas\": null,\n        \"id\": \"1\",\n        \"idComposicaoPelagem\": \"50\",\n        \"idCorOlhoDir\": \"39902\",\n        \"idCorOlhoEsq\": \"39902\",\n        \"idEspecie\": \"5\",\n        \"idPelagem\": \"6\",\n        \"idRaca\": \"34\",\n        \"idResenhaAnterior\":\"0\",\n        \"idSexo\": \"2501\",\n        \"machoCastrado\": \"N\",\n        \"microChipAnimal\": \"123456989012377\",\n        \"microchipMae\": \"\",\n        \"nomeAnimal\": \"MACADANIAS111\",\n        \"numeroAssocRaca\": \"\",\n        \"numeroPassaporte\": \"\",\n        \"outrasCaracteristicas\": null,\n        \"quantAnimaisEq\": \"05\",\n        \"quantAnimaisAs\": \"0\",\n        \"quantAnimaisMu\": \"02\",\n        \"retifica\": false\n    }\n}"
    let postData = parameters.data(using: .utf8)

    var request = URLRequest(url: URL(string: "https://MY_ENDPOINT/validaResenha")!,timeoutInterval: Double.infinity)
    request.addValue("Basic THIS_IS_BASIC_AUTH_VALIDATION", forHTTPHeaderField: "Authorization")
    request.addValue("application/json", forHTTPHeaderField: "Content-Type")
    request.addValue("JSESSIONID=0000_B1PZRSVcyzEkDUkMxvk9ig:18jgnbg8n; LtpaToken2=q9JsIHVBKPsCYKGRohXJAKnXED3HRXXGlaswzYpnPSLS0B+c/WbiW+QcUMwmw/8xcb7VL1bVvbUh0ZAvMR3TNcGudWUkg9f0z5K0n0P2pJ5Frte6trqVLhPoKuI5E7zwC3Yg+XCsPBNFy0aukkrWNiCWAqbyGI3nir6UuX5qLER4H+bEYfk4cFw58eHGSIN/FTVjH7WW7aEAfkYNXxWzSDnNVJDtihZVXw+oJSfe74Vz8Scv33cPPZH2W74KvKwj09FOo+EJsvFcC2aDUQclYqwuo91HIaIpqcYb17cSCX95xn9KHErlC48M1bU03txKaDVcmUrOCrveCs7pVPNCz066cil5bzjXeYlXDlmUw5MT45Zgg8EmaJ9gi+iC2zPCU+W088OGEriphXpto40ww3irTN9rtnhIppB5U+drRFW6u25UmDkAjx899TNzC/XsJqkRXn9GinQv6xiD+Axnv3AgudQZBGyeYcNNJDRfA+jzbr6HE1NuNSkxY6aP1OvCLGkNDSA16chO7f4IjjR9jkvDH2m3+ajxa7as1rVNK9R0HHcZJLExvOJn3sJ1LKDwMNPTDjKGPLuWOVwTPQL2pzIitLjkeyx8A2Qcqo5p8U/+aa11Z/x8WA0bQRscZLWMtEHE6WLnHFqBaylCAzARF0Y5cOI/TYCW2xd99ux2WaJnumVlskr2uNCWdwSMOp78gvmzdmonQUH0Ko/k4wa8HcJPyMV5NK52gArIyGmeKXo=", forHTTPHeaderField: "Cookie")

    request.httpMethod = "POST"
    request.httpBody = postData

    let task = URLSession.shared.dataTask(with: request) { data, response, error in
      guard let data = data else {
        print(String(describing: error))
        semaphore.signal()
        return
      }
      print(String(data: data, encoding: .utf8)!)
      semaphore.signal()
    }

    task.resume()
    semaphore.wait()
    
    print("end")

但我现在收到 401 错误。出于某种原因,基本身份验证未被代码或服务器接受。 我检查了用户和密码,它们是正确的。

我找到了解决问题的方法。

我在常量文件中使用“http://MY_ENDPOINT/validaResenha”而不是“https://MY_ENDPOINT/validaResenha”。

将“s”添加到“http”字母(它变成“https”)后,一切开始为我工作。

奇怪的是,由于从 HTTP 重定向到 HTTPS,GET 和 PUT 方法工作正常,但在 POST 调用的情况下,我遇到了这个错误。

现已修复。

iOS 阻止 HTTP 使用 HTTPS 或添加到您的 Info.plist 文件