【问题标题】:can not get access token from api无法从 api 获取访问令牌
【发布时间】:2018-10-10 10:01:52
【问题描述】:

enter image description here我是 Swift 新手,遇到了一个问题。欢迎任何帮助和建议,我也看过 Alomofire,但由于一些错误我无法设置 Alamofire,而且我需要 Alamofire 的帮助:|

request.addValue("application/json", forHTTPHeaderField:   
      "Accept")
    request.addValue("application/x-www-form-urlencoded", 
      forHTTPHeaderField:   "Content-Type")
    let postString = ["grant_type"  : "password" ,
                      "username"    : EntPhoneNumber.text! ,
                      "password"    : EntPassword.text! ,] as [String : 
 Any]
    do {


        request.httpBody = try JSONSerialization.data(withJSONObject: 
 postString)
    }catch let error {
        print(error.localizedDescription)
        DisplayMessage(UserMessage: "Something went wrong , please try 
 again!")
        return
    }

    let task = URLSession.shared.dataTask(with: request)
    {
        (data : Data? , response : URLResponse? , error : Error?) in

        self.removeActivtyIndicator(activityIndicator: 
 MyActivityIndicator)



        if error != nil
        {
            self.DisplayMessage(UserMessage: "1Could not successfully 
 perform this request , please try again later.")
            print("error = \(String(describing : error))")
            return
        }



        // let's convert response sent from a server side code to a 
 NSDictionary object:

        do { let json = try JSONSerialization.jsonObject(with: data!, 
 options: .mutableContainers) as? NSDictionary

            print(json!)
            if let parseJSON = json
            {
                let userID = parseJSON["grant_type"] as? String
                print("access_token : \(String(describing: userID))");

                if userID == nil
                {
                    //display an alert dialog with a friendly error 
message
                    self.DisplayMessage(UserMessage: "2Could not 
successfully perform this request , please try later.")
                    return
                }
                else
                {
                    self.DisplayMessage(UserMessage: "3successfully 
loged in.")
                }
            }

...

如您所见,这是我的代码,我正在向 api 发送请求以获取 access_token,但我收到一个错误:

{error = "invalid_request"; "error_description" = "缺少必需的 'grant_type' 参数。"; }

这些是我应该发布到 API 的参数,在邮递员中它可以正常工作,但我的代码在编译器中根本不起作用。

【问题讨论】:

  • 添加您要发布的网址?
  • @ChanWarde let myUrl = URL(string: "api.nahadeh.com/connect/token")
  • 要将 Alamofire 添加到您的项目中,您需要使用 CocoaPods,github.com/Alamofire/Alamofire#installation
  • 所以...你在哪里设置了标题中的Content Length?因为我看不到那部分。
  • @holex 我没有在邮递员中设置内容长度,但它有效

标签: ios iphone swift api http


【解决方案1】:

你太复杂了

let postString = ["grant_type"  : "password" ,
                      "username"    : EntPhoneNumber.text! ,
                      "password"    : EntPassword.text! ,] as [String :
                        Any]

    Alamofire.request(URL, method: .post, parameters: postString, encoding: URLEncoding.methodDependent, headers: nil).responseJSON { response in

        if let json = response.result.value {
            print("Response: ",json)
        }

    }

试试这个。

这就是你所需要的。如果您有任何疑问,请在此处提问。

【讨论】:

  • 我真的很喜欢使用 Alamofire ,但我不知道如何将它添加到我的项目中!你能如何添加alamofire
  • 在您的项目中使用可可豆荚或简单地拖放框架
  • 我也必须使用这个“request.addValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")" 标头必须是这个
【解决方案2】:

点击此链接使用 CocoaPods 安装 Alamofire

https://www.raywenderlich.com/156971/cocoapods-tutorial-swift-getting-startedenter link description here

我已经为 API 请求创建了这个自定义方法。

func request(_ method: HTTPMethod
    , _ URLString: String
    , parameters: [String : AnyObject]? = [:]
    , headers: [String : String]? = [:]
    , completion:@escaping (Any?) -> Void
    , failure: @escaping (Error?) -> Void) {

    Alamofire.request(URLString, method: method, parameters: parameters, encoding: JSONEncoding.default, headers: headers)
        .responseJSON { response in

            switch response.result {
            case .success:
                completion(response.result.value!)
            case .failure(let error):
                failure(error)
            }
    }
}

【讨论】:

  • 我点击链接并安装,它添加了 pods_.framework 仍然无法添加 alamofire!!!!
  • 我在欢迎页面打开了我的项目:| :),我对 Swift 很困惑 :|
  • 什么欢迎页面?我在问您是否打开了 .xcodeProj 文件或 .xcworkspcae 文件。转到您的项目所在的文件夹
  • 监听当你用 pod 安装任何库时,你必须打开 .xcworkspace 文件而不是 .xcodeproje。从现在开始打开 ​​.xcwprkspace,它将位于同一目录中
  • 它在 .xcworkspace 中也不起作用!框架是红色的,因为它们应该是黑色的!
【解决方案3】:

您需要在发送请求时对查询中的登录名和密码参数进行编码。让我们创建一个单独的 Network 类,它具有 loginRequest(username:password) 函数,该函数使用用户名和密码参数向服务器发出 API 请求。 login 方法有一个 closure ,它要么返回 userId 字符串,要么返回错误。

class Networking {

    enum NetworkError: Error {
        case parsingData
        case jsonParsing
        case emptyData
        case apiError(error: Error)
    }

    func parseJSON(from data: Data) throws -> Any {
        do {
            let json = try JSONSerialization.jsonObject(with: data, options: .allowFragments)
            return json
        } catch {
            return error
        }
    }

    func loginRequest(username: String, password: String, completion: @escaping (String?, NetworkError?) -> ()) {

        var request = URLRequest(url: URL(string: "api.nahadeh.com/connect/token")!)
        request.addValue("application/json", forHTTPHeaderField: "Accept")
        request.addValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")

        let queryParams = "grant_type=password&username=\(username)&password=\(password)"
        request.httpBody = queryParams.data(using: .utf8, allowLossyConversion: false)

        URLSession.shared.dataTask(with: request) { (data, response, error) in

            guard error != nil else {
                completion(nil, NetworkError.apiError(error: error!))
                return
            }

            guard let data = data else {
                return completion(nil, NetworkError.emptyData)
            }

            do {
                let json = try self.parseJSON(from: data) as! [String: Any]
                guard let accessToken = json["access_token"] as? String else {
                    completion(nil, NetworkError.jsonParsing)
                    return
                }
                completion(accessToken, nil)
            } catch {
                completion(nil, NetworkError.jsonParsing)
            }
        }.resume()
    }
}

现在,您可以从 UIViewController 子类创建 Networking 类的实例并使用用户名和密码参数调用登录方法

class LoginViewController: UIViewController {

    let networking = Networking()

    func login(username: String, password: String) {

        networking.loginRequest(username: username, password: password) { (token, error) in

            if let token = token {
                print(token)
                self.displayMessage("Successfully loged in. Go to home screen")
                return
            }

            if let nError = error {
                switch nError {
                case .jsonParsing:
                    self.displayMessage("jsonParsingError")
                case .emptyData:
                    self.displayMessage("emptyData")
                case .apiError(let error):
                    print(error.localizedDescription)
                    self.displayMessage("Could not successfully perform this request , please try later.")
                case .parsingData:
                    self.displayMessage("parsingData")
                }
            }
        }
    }

    func displayMessage(_ message: String, completion: (() -> Void)? = nil) {
        let alert = UIAlertController(title: "Message", message: message, preferredStyle: .alert)
        let okAction = UIAlertAction(title: "OK", style: .default, handler: nil)
        alert.addAction(okAction)
        present(alert, animated: true, completion: completion)
    }
}

使用Alamofire很容易发出API请求,只需传递参数,它就会为你完成工作

  func loginRequest(username: String, password: String, completion: @escaping (String?, Error?) -> ()) {

        let params: [String: String] = [
            "grant_id": "password",
            "username": username,
            "password" : password
        ]

        Alamofire.request("api.nahadeh.com/connect/token", method: .post, parameters: params, encoding: .httpBody, headers: nil).validate().response { (response) in
            switch response.result {
            case .success(let value):
                let accessToken = value["access_token"]
                completion(accessToken, nil)
            case .failure(let error):
                completion(nil, error)
            }
        }
    }

【讨论】:

  • 我应该将您发送的这个代码添加到我的代码中,还是用这个更改它?
  • 为了清楚起见,您可以添加此代码或替换相关部分以检查它是否有效。
  • 我用你的代码改变了我的代码,现在我应该如何调用这些函数?
  • 只需将 LoginViewController 中的登录功能复制粘贴到您的 ViewController 中,然后从 viewDidLoad 方法中调用 login(username: "username", password: "password") 方法
  • 我认为这个方法应该可行,但我对 func 和 classes 有点困惑,你能把它们完全排序并再次发送吗?
猜你喜欢
  • 2018-01-08
  • 2020-06-12
  • 2016-02-09
  • 2020-10-09
  • 1970-01-01
  • 1970-01-01
  • 2023-04-05
  • 2022-01-01
相关资源
最近更新 更多