在 Swift 中,如何使用包含同一键的多个值的查询参数来构建 URL?

我在我的 iOS 应用程序中使用 AFNetworking,对于它发出的所有 GET 请求,我从一个基本 URL 构建 URL,然后使用 NSDictionary 键值对添加参数。

问题是对于不同的值我需要相同的键。

这里有一个例子,我需要的最终 URL 看起来像-

Http://example.com/.....&id=21212&id=21212&id=33232

在 NSDictionary 中不可能在同一个键中有不同的值。

let productIDSet: Set = [prodIDArray]
let paramDict = NSMutableDictionary()
paramDict.setObject(productIDSet, forKey: "id")
87743 次浏览

我想你只需要做这样的事情:

let params = ["id" : [1, 2, 3, 4], ...];

将被编码成: ... id% 5B% 5D = 1 & id% 5B% 5D = 2 & id% 5B% 5D = 3 & id% 5B% 5D = 4...

所有你需要的是 URLComponents(或者在 Obj-C 中的 NSUL 组件)。基本思想是为您的 id 创建一系列查询项。下面是你可以粘贴到操场上的代码:

import Foundation
import XCPlayground


let queryItems = [URLQueryItem(name: "id", value: "1"), URLQueryItem(name: "id", value: "2")]
var urlComps = URLComponents(string: "www.apple.com/help")!
urlComps.queryItems = queryItems
let result = urlComps.url!
print(result)

您应该会看到

Www.apple.com/help?id=1&id=2

func queryString(_ value: String, params: [String: String]) -> String? {
var components = URLComponents(string: value)
components?.queryItems = params.map { element in URLQueryItem(name: element.key, value: element.value) }


return components?.url?.absoluteString
}

方法1

它可以将 QueryItem添加到您现有的 URL 中。

extension URL {


func appending(_ queryItem: String, value: String?) -> URL {


guard var urlComponents = URLComponents(string: absoluteString) else { return absoluteURL }


// Create array of existing query items
var queryItems: [URLQueryItem] = urlComponents.queryItems ??  []


// Create query item
let queryItem = URLQueryItem(name: queryItem, value: value)


// Append the new query item in the existing query items array
queryItems.append(queryItem)


// Append updated query items array in the url component object
urlComponents.queryItems = queryItems


// Returns the url from new url components
return urlComponents.url!
}
}

怎么用

var url = URL(string: "https://www.example.com")!
let finalURL = url.appending("test", value: "123")
.appending("test2", value: nil)

方法2

在此方法中,URL 将自动更新。

extension URL {


mutating func appendQueryItem(name: String, value: String?) {


guard var urlComponents = URLComponents(string: absoluteString) else { return }


// Create array of existing query items
var queryItems: [URLQueryItem] = urlComponents.queryItems ??  []


// Create query item
let queryItem = URLQueryItem(name: name, value: value)


// Append the new query item in the existing query items array
queryItems.append(queryItem)


// Append updated query items array in the url component object
urlComponents.queryItems = queryItems


// Returns the url from new url components
self = urlComponents.url!
}
}


// How to use
var url = URL(string: "https://www.example.com")!
url.appendQueryItem(name: "name", value: "bhuvan")

附加查询条目的 URL 扩展,类似于 Bhuvan Bhatt 的想法,但带有不同的签名:

  • 它可以检测故障(通过返回 nil而不是 self) ,从而允许自定义处理 URL 不符合 RFC 3986的情况。
  • 它通过实际将任何查询项作为参数传递,允许 nil 值。
  • 为了提高性能,它允许一次传递多个查询项。
extension URL {
/// Returns a new URL by adding the query items, or nil if the URL doesn't support it.
/// URL must conform to RFC 3986.
func appending(_ queryItems: [URLQueryItem]) -> URL? {
guard var urlComponents = URLComponents(url: self, resolvingAgainstBaseURL: true) else {
// URL is not conforming to RFC 3986 (maybe it is only conforming to RFC 1808, RFC 1738, and RFC 2732)
return nil
}
// append the query items to the existing ones
urlComponents.queryItems = (urlComponents.queryItems ?? []) + queryItems


// return the url from new url components
return urlComponents.url
}
}

用法

let url = URL(string: "https://example.com/...")!
let queryItems = [URLQueryItem(name: "id", value: nil),
URLQueryItem(name: "id", value: "22"),
URLQueryItem(name: "id", value: "33")]
let newUrl = url.appending(queryItems)!
print(newUrl)

产出:

Https://example.com/...?id&id=22&id=33

在多参数快速形成 URL 中

func rateConversionURL(with array: [String]) -> URL? {
var components = URLComponents()
components.scheme = "https"
components.host = "example.com"
components.path = "/hello/"
components.queryItems = array.map { URLQueryItem(name: "value", value: $0)}


return components.url
}

二零一九年

private func tellServerSomething(_ d: String, _ s: String) {
    

var c = URLComponents(string: "https://you.com/info")
c?.queryItems = [
URLQueryItem(name: "description", value: d),
URLQueryItem(name: "summary", value: s)
]
guard let u = c?.url else { return print("url fail") }
do {
let r = try String(contentsOf: u)
print("Server response \(r)")
}
catch { return print("comms fail") }
}

百分号编码都处理好了。

更新 iOS 16,Swift 5.7 +

有一种更简单的方法可以实现这一点:

var url = URL(string: "http://google.com/search")
url?.append(queryItems: [URLQueryItem(name: "q", value: "soccer")])
print(url) // http://www.google.com/search?q=soccer