返回

API请求集中管理:单一类实践方案详解

IOS

集中管理API请求:单一类实践方案

在应用开发中,尤其是在处理多个视图控制器需要与API交互时,重复编写API调用逻辑和URL定义会导致代码冗余、维护困难。将所有API链接集中到一个类中,能够显著提升代码的复用性、可读性和可维护性。该方案的核心是将API请求的逻辑封装在一个单一的类中,并通过调用方法的方式进行使用,而不是在各个视图控制器中重复定义URL。

问题剖析

每个视图控制器都包含各自独立的API URL,直接在视图控制器中处理HTTP请求:

  1. 重复代码: 各处都需要定义基本URL、请求方法和数据解析。
  2. 难以维护: 如果基本URL或API路径变更,需在所有视图控制器中手动修改。
  3. 不易复用: 逻辑散落在各处,难以复用请求相关的通用功能(如错误处理、参数格式化等)。
  4. 耦合性高: 视图控制器与特定API紧密绑定,不易修改和扩展。

解决方案

将所有API端点URL以及HTTP请求操作整合进一个独立类中,可以有效解决上述问题。这通过定义一个中心化的服务类,其中包含了所有API端点,并将与这些端点进行通信的逻辑封装起来实现。这个服务类随后可在应用程序中的任何地方使用,通过简单地调用特定方法进行网络请求。

创建API服务类

建立一个类,集中存储所有API端点URL以及发送请求的方法。以 Swift 语言(兼容 Swift 2.0)为例,我们展示具体的代码。

import Foundation

class APIService {
    
    static let sharedInstance = APIService()
    
    private let baseURL = "http://some_url"  // 配置基本URL
    
    //  定义所有 API 端点
    enum Endpoint: String {
        case login = "/login.php"
        case register = "/register.php"
        case userData = "/user.php"
        case productList = "/products.php"
        case uploadImage = "/upload_image.php"
        // 更多 API 端点
    }

    private init() { } // 防止外部实例化

    //  请求数据通用函数
    func request(endpoint: Endpoint, parameters: [String: AnyObject]?, completion: (NSData?, NSURLResponse?, NSError?) -> Void) {
       
        let urlString = baseURL + endpoint.rawValue // 构建请求完整URL
        guard let url = NSURL(string: urlString) else {
            let error = NSError(domain: "APIServiceError", code: 0, userInfo: [NSLocalizedDescriptionKey: "URL生成失败"])
             completion(nil, nil, error)
             return
         }

       
        let request = NSMutableURLRequest(URL: url)
        request.HTTPMethod = "POST"   //根据需求调整
        request.setValue("application/json", forHTTPHeaderField: "Content-Type")

        if let parameters = parameters {
          do{
            request.HTTPBody = try NSJSONSerialization.dataWithJSONObject(parameters, options: NSJSONWritingOptions.PrettyPrinted)
           } catch let error as NSError{
             completion(nil, nil, error)
               return
           }

         }

        let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { (data, response, error) in
           completion(data, response, error)
         }
       
        task.resume()
     }
}

上述代码中:

  • 创建了单例sharedInstance用于访问唯一实例。
  • baseURL常量配置你的API基本URL。
  • Endpoint枚举维护了所有API端点的相对路径,枚举的优点是具有类型安全性。
  • request(endpoint:parameters:completion:) 方法封装了通用请求逻辑,方便传递不同请求参数,通过闭包返回结果。该方法根据端点类型拼合URL并发出请求。NSJSONSerialization 进行参数编码,需要将你的参数整理成对应的格式,比如需要修改请求类型,在此函数中调整request.HTTPMethod = "POST",如果是GET则使用对应的构造URL的方式拼接参数。

如何使用

在任何视图控制器中,调用APIService.sharedInstance 来请求 API,以下是一个如何使用的示例:

import UIKit

class LoginViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        let loginParams: [String: AnyObject] = [ "username": "testuser","password": "password"]
          APIService.sharedInstance.request(.login,parameters: loginParams) { (data, response, error) in

                if let error = error {
                      print("错误信息: \(error)")
                }
              else if let data = data {

                  //根据你的API定义数据结构 进行转换
                   do {
                    let json = try NSJSONSerialization.JSONObjectWithData(data, options: .AllowFragments)
                    print("登录成功:\(json)")

                   }catch let jsonError as NSError{

                       print("JSON 解析失败:\(jsonError)")
                       return

                   }
                }
             else{
                   print("未知的请求问题")
              }

            }

      }
 }


class RegisterViewController: UIViewController{
    override func viewDidLoad() {
          super.viewDidLoad()

          let registerParams: [String: AnyObject] = ["email": "user@email.com", "new_password": "password", "password_confirm":"password"]

        APIService.sharedInstance.request(.register, parameters: registerParams) { (data, response, error) in
                   if let error = error{

                      print("注册失败, 错误信息:\(error)")

                  }else if let data = data {
                      do {
                           let json = try NSJSONSerialization.JSONObjectWithData(data, options: .AllowFragments)
                          print("注册成功,数据:\(json)")
                      }catch let jsonError as NSError{
                         print("Json解析失败:\(jsonError)")
                            return
                        }
                  }
                 else{
                   print("未知的请求问题")
                 }
         }
      }
}


在上面的示例中,只需要指定 API 的 Endpoint 就可以完成 HTTP 请求,然后使用闭包来处理请求返回的结果(包括错误、数据和状态),而不需要重复的 URL 代码,提高了代码的复用率,可读性和易于维护。你只需要添加新的 case 在enum Endpoint, 同时创建对应的请求方法即可完成增加一个API接口。

安全建议

  • 将API秘钥和敏感信息存储在服务器端,避免直接嵌入客户端代码。
  • 对所有输入参数进行验证,防止安全漏洞(如 SQL 注入)。
  • 对于重要的网络请求,使用HTTPS进行数据加密传输。
  • 实施速率限制和请求监控,防御恶意攻击。

这个方法通过分离网络请求代码和视图控制器的UI 代码,提升了整个项目的结构和组织。在应用设计时使用此类方案,可以更方便、高效地进行软件维护和功能拓展。