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

Posted

技术标签:

【中文标题】如何在 Swift 中使用包含多个值的查询参数构建 URL?【英文标题】:How can I build a URL with query parameters containing multiple values for the same key in Swift? 【发布时间】:2016-03-07 18:10:53 【问题描述】:

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

问题是我需要为不同的值使用相同的键。

这是我需要最终 URL 的示例 -

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

在 NSDictionary 中不可能在同一个键中有不同的值。所以我尝试了 NSSet 但没有成功。

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

【问题讨论】:

【参考方案1】:

您只需要URLComponents(或Obj-C 中的NSURLComponents)。基本思想是为您的 id 创建一堆查询项。以下是您可以粘贴到 Playground 的代码:

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

【讨论】:

太棒了。感谢您的回答。我尝试循环并在 for 循环中添加值,因为我的 ID 在数组中,但我面临很多问题。您能否建议我如何在循环中添加值?非常感谢。 当然,只需确保将 queryItems 数组声明为 var,然后您可以在循环中添加新项目 @AbhishekDwivedi 抱歉@Daniel 打扰了你,但这是我正在尝试但无法做到的。不知道问题是什么:( var queryItems = [NSURLQueryItem]() let urlComps = NSURLComponents(string: "www.apple.com/help")! for var i = 0 ; i 您不需要在循环中创建查询项数组。只需删除方括号,你应该会很好@AbhishekDwivedi 我的网址如下abcd.com/json/trend/id/12/key/23456 我怎样才能做到这一点?我正在使用 alamofire 4.0【参考方案2】:

方法一

它可以将 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)

方法二

此方法会自动更新网址。

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")

【讨论】:

【参考方案3】:
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

【讨论】:

【参考方案4】:

附加查询项的 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 中允许多次使用相同的键不是一个好主意 @atulkhatri 虽然 RFC 3986 允许,但我很清楚,例如 on Windows Phone 7/8, the Operating System won't even let you handle URLs with duplicate keys。所以我完全同意这不是最佳做法。因此,它的使用将取决于您的 API。这是how I filter duplicate keys in Swift:使用其中的代码,您可以根据需要添加queryItems.unique(for: \.name) 我完全理解你的意图,但我觉得它是一个前端代码,应用程序不知道服务器将如何处理它。所以为了更安全,我认为最好不要有这种不一致的查询参数。【参考方案5】:

2019

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") 

百分比编码和其他一切都得到处理。

【讨论】:

【参考方案6】:

在具有多个参数的 Swift Forming 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
    

【讨论】:

【参考方案7】:

帮帮我

斯威夫特 5**

let url = URL(string: "https://example.com")
let path = "/somePath?"
let urlWithPath = url?.appendingPathComponent(path).absoluteString.removingPercentEncoding
print(urlWithPath!)

【讨论】:

不,这不回答如何构建query parameters containing multiple values for the same key【参考方案8】:

我猜你只需要这样做:

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

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

【讨论】:

如果您正在使用 swift,我建议您使用 Alamofire

以上是关于如何在 Swift 中使用包含多个值的查询参数构建 URL?的主要内容,如果未能解决你的问题,请参考以下文章

如何在流分析中查询 JSON 以使包含多个数组值的 JSON 脱离

如何使用swift在字典中添加多个参数[String,Dictionary]?

在一个字段中为多个值构建Lucene查询

如何在 jdbcTemplate 中为具有相同值的多个参数标记传递参数?

如何将空值显式插入参数化查询?

您如何最好地为多个查询参数构建 DynamoDb