Swift如何向函数传递参数字典并发起GET请求?
解决方案:动态传递请求参数并安全构建URL
咱们可以通过重构makeRequest函数,让它支持动态传入任意查询参数(包括client_id或无参数),同时用更安全的方式构建URL(避免硬编码和字符编码问题)。以下是具体实现步骤:
1. 重构makeRequest函数,支持动态参数
首先,给函数添加一个可选的queryParameters参数(默认空字典),然后用URLComponents来构建带参数的URL——这种方式能自动处理特殊字符的编码,还能灵活添加参数。同时修复之前token强制解包的崩溃风险:
func makeRequest<T>(endpoint: String, queryParameters: [String: String] = [:], completionHandler: @escaping (ApiContainer<T>?, Error?) -> ()) { // 先安全获取token,避免强制解包 guard let token = DAKeychain.shared["token"] else { print("Error: token not found in keychain") let error = BackendError.urlError(reason: "Missing authentication token") completionHandler(nil, error) return } // 用URLComponents构建URL,比直接拼接字符串更安全 guard var components = URLComponents(string: endpoint) else { print("Error: cannot create URL components") let error = BackendError.urlError(reason: "Could not create URL components") completionHandler(nil, error) return } // 初始化查询参数列表,先添加必填的token var queryItems = [URLQueryItem(name: "token", value: token)] // 遍历传入的动态参数,逐个添加到查询列表 for (key, value) in queryParameters { queryItems.append(URLQueryItem(name: key, value: value)) } components.queryItems = queryItems guard let url = components.url else { print("Error: cannot create final URL") let error = BackendError.urlError(reason: "Could not build final URL") completionHandler(nil, error) return } print(url) var urlRequest = URLRequest(url: url) let session = URLSession.shared urlRequest.httpMethod = "GET" urlRequest.addValue("application/json", forHTTPHeaderField: "Content-Type") urlRequest.addValue("application/json", forHTTPHeaderField: "Accept") let task = session.dataTask(with: urlRequest) { (data, response, error) in guard let responseData = data else { print("Error: did not receive data") completionHandler(nil, error) return } guard error == nil else { completionHandler(nil, error!) return } do { let response = try JSONDecoder().decode(ApiContainer<T>.self, from: responseData) completionHandler(response, nil) } catch { print("error trying to convert data to JSON") print(error) completionHandler(nil, error) } } task.resume() }
2. 修改getContacts函数,传递client_id参数
现在你可以在调用makeRequest时,通过queryParameters参数传入client_id(如果需要,后续也能换成动态值,比如从配置或用户输入获取):
func getContacts() { // 传入client_id参数,这里保留你原来的测试值60 makeRequest(endpoint: "http://blog.local:4711/api/contacts/all", queryParameters: ["client_id": "60"]) { (container: ApiContainer<Contact>?, error: Error?) in if let error = error { print("error calling GET on /api/contacts/all") print(error) return } // 用可选绑定替代强制解包,避免崩溃 if let contacts = container?.result { self.tableArray = contacts DispatchQueue.main.async { self.tableView.reloadData() } } else { print("Error: no contacts data received") } } }
3. 其他场景的调用示例
- 无参数传递:直接省略
queryParameters即可,函数会自动只传token:makeRequest(endpoint: "http://blog.local:4711/api/user/profile") { (container: ApiContainer<User>?, error: Error?) in // 处理结果逻辑 } - 多参数传递:比如同时传
client_id和分页参数page:makeRequest(endpoint: "http://blog.local:4711/api/contacts/all", queryParameters: ["client_id": "60", "page": "1"]) { ... }
这样修改后,你的请求函数既保留了GET传token的逻辑,又能灵活传递任意参数(或无参数),还解决了硬编码和URL编码的潜在问题,同时代码更安全稳定。
内容的提问来源于stack exchange,提问作者Renan Aguiar
相关产品推荐
相关产品推荐

