【问题标题】:How can I build a URL with query parameters containing multiple values for the same key in Swift?如何在 Swift 中使用包含多个值的查询参数构建 URL?
【发布时间】: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")

【问题讨论】:

    标签: ios swift swift2 nsurl


    【解决方案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
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2010-10-30
            相关资源
            最近更新 更多