将 CURL 转换为 Swift

Convert CURL to Swift

我需要将 Microsoft Azure Cloud 的以下 curl 调用转换为 Swift:

curl -X POST "https://api.cognitive.microsofttranslator.com/translate?api-version=3.0&to=zh-Hans&toScript=Latn" -H "Ocp-Apim-Subscription-Key: <client-secret>" -H "Content-Type: application/json; charset=UTF-8" -d "[{'Text':'Hello, what is your name?'}]"

我需要将 curl 的 JSON 调用转换为 Swift。问题是我没有使用 JSON 调用的经验,也不知道如何包含 headers、body 和参数。 所以我尝试了以下代码:


let apiKey = "..."
let location = "..."

class AzureManager {
    
    static let shared = AzureManager()
    
    func makeRequest(json: [String: Any], completion: @escaping (String)->()) {
        
        guard let url = URL(string: "https://api.cognitive.microsofttranslator.com/translate"),
              let payload = try? JSONSerialization.data(withJSONObject: json) else {
            return
        }
        
        var request = URLRequest(url: url)
        request.httpMethod = "POST"
        request.addValue(apiKey, forHTTPHeaderField: "Ocp-Apim-Subscription-Key")
        request.addValue(location, forHTTPHeaderField: "Ocp-Apim-Subscription-Region")
        request.addValue("application/json", forHTTPHeaderField: "Content-type")
        request.addValue("NaiVVl3DEFG3jdE5DE1NFAA6EABC", forHTTPHeaderField: "X-ClientTraceId")
        request.httpBody = payload

        URLSession.shared.dataTask(with: request) { (data, response, error) in
            guard error == nil else { completion("Error::\(String(describing: error?.localizedDescription))"); return }
            guard let data = data else { completion("Error::Empty data"); return }
            
            let json = try? JSONSerialization.jsonObject(with: data, options: .allowFragments) as? [String: Any]

            if let json = json,
               let choices = json["translations"] as? [String: Any],
               let str = choices["text"] as? String {
                completion (str)
            } else {
                completion("Error::nothing returned")
            }
            
        }.resume()
    }
}

然后这样称呼它:

let jsonPayload = [
           "api-version": "3.0",
           "from": "en",
           "to": "it",
           "text": "Hello"
           ] as [String : Any]
   
AzureManager.shared.makeRequest(json: jsonPayload) { [weak self] (str) in
     DispatchQueue.main.async {
           print(str)
     }
}

嗯,我得到的错误是:

    Optional(["error": {
        code = 400074;
        message = "The body of the request is not valid JSON.";
    }])

并且:

错误::没有返回

Microsoft Azure Translator 文档如下: https://docs.microsoft.com/de-de/azure/cognitive-services/translator/reference/v3-0-translate

让我们分析一下您的 cURL command,让我们用换行使其更具可读性。如果你想让它在 Terminal.app 中这样工作,只需在行尾添加 \

curl \
-X POST \ 
"https://api.cognitive.microsofttranslator.com/translate?api-version=3.0&to=zh-Hans&toScript=Latn" \
-H "Ocp-Apim-Subscription-Key: <client-secret>" \ 
-H "Content-Type: application/json; charset=UTF-8" \ 
-d "[{'Text':'Hello, what is your name?'}]"

-H:设置为addValue(_,forHTTPHeaderField:) -d:设置为httpBody = 长的URL,就是request.url

cURL 命令和 URLRequest you 模式之间有两个主要区别。

首先,您混合了负载和 URL 设置。

url 应该是 "https://api.cognitive.microsofttranslator.com/translate?api-version=3.0&to=zh-Hans&toScript=Latn",而不是 "https://api.cognitive.microsofttranslator.com/translate",你把 api-versiontotoScript(那一个不见了方式)在 httpBody 内。 将它们放入 URL 中。您可以使用 URLQueryItem 来正确格式化它们。参见

现在,一旦你解决了这个问题,就会出现第二个问题:

[{'Text':'Hello, what is your name?'}],我会绕过它使用单引号的奇怪事实,但是,这里 JSON 是顶级数组,而不是字典。此外,它是 Text,而不是 text(可能区分大小写)。

如果您想查看您在 httpBody 中发送的内容,请不要犹豫:

if let jsonStr = String(data: request.httpBody ?? Data(), encoding: .utf8) {
    print("Stringified httpBody: \(jsonStr)")
}

因此请修改您的参数,直到它与工作中的 cURL 命令中的 on 相匹配。如前所述,它是一个数组,而不是字典。

最后,避免使用try?,请正确使用do/try/catch,因为如果它失败了,至少你需要知道它。
如果您不希望在顶层出现 JSON 字符串,则无需使用 .allowFragments。在这里,您期待的是字典。
我建议现在在 Swift 4+ 中使用 Codable 而不是 JSONSerialization.

编辑:查看文档,当您混合 parameters/query 时,请记住: “查询参数”,用于 URLQueryItems,在 URL 中。 请求正文:那是 httpBody.