如何http快速发布特殊字符

use*_*300 3 php swift

我正在使用以下内容将电子邮件和密码发布到我的服务器(php脚本)。我遇到的问题是密码包含一个特殊字符(特别是&符号),该字符似乎被剥夺了。我猜想是因为它认为要传递其分离变量。如何在不删除它的情况下传递此char?

let myURL = NSURL(string: "my script url here")
let request = NSMutableURLRequest(URL: myURL!)
request.HTTPMethod = "POST"

let postString = "email=\(userEmailText)&password=\(userPasswordText)"

request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding)
Run Code Online (Sandbox Code Playgroud)

Rob*_*Rob 5

您应该警惕使用它,NSURLComponents因为NSURLQueryItem可能会百分号转换所讨论的字符&,而不会百分号转换+字符(PHP会将其解释为符合W3C规范x-www-form-urlencoded的空格)。由于queryItems文件说:

注意

RFC 3986指定必须在URL的查询组件中对哪些字符进行百分比编码,但不指定应如何解释这些字符。分隔键/值对的使用是一种常见的约定,但尚未由规范进行标准化。因此,您可能会遇到遵循此约定的其他实现的互操作性问题。

潜在的互操作性问题的一个著名示例是如何处理加号(+)字符:

根据RFC 3986,加号是查询中的有效字符,不需要进行百分比编码。但是,根据W3C关于URI寻址的建议,加号保留为查询字符串(例如?greeting=hello+world)中空格的简写形式。

如果您的值可能包含+字符,则可以为百分比转义您自己添加到URL查询的值留出几种选择:

  1. 您可以构建自己CharacterSet的要转义的字符,然后addingPercentEncodingForURLQueryValue在Swift 3中使用:

    extension String {
    
        /// Returns a new string made from the `String` by replacing all characters not in the unreserved
        /// character set (as defined by RFC3986) with percent encoded characters.
    
        func addingPercentEncodingForURLQueryValue() -> String? {
            let allowedCharacters = CharacterSet.urlQueryValueAllowed()
            return addingPercentEncoding(withAllowedCharacters: allowedCharacters)
        }
    
    }
    
    extension CharacterSet {
    
        /// Returns the character set for characters allowed in the individual parameters within a query URL component.
        ///
        /// The query component of a URL is the component immediately following a question mark (?).
        /// For example, in the URL `http://www.example.com/index.php?key1=value1#jumpLink`, the query
        /// component is `key1=value1`. The individual parameters of that query would be the key `key1`
        /// and its associated value `value1`.
        ///
        /// According to RFC 3986, the set of unreserved characters includes
        ///
        /// `ALPHA / DIGIT / "-" / "." / "_" / "~"`
        ///
        /// In section 3.4 of the RFC, it further recommends adding `/` and `?` to the list of unescaped characters
        /// for the sake of compatibility with some erroneous implementations, so this routine also allows those
        /// to pass unescaped.
    
    
        static func urlQueryValueAllowed() -> CharacterSet {
            return CharacterSet(charactersIn: "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._~/?")
        }
    
    }
    
    Run Code Online (Sandbox Code Playgroud)
  2. Alamofire采取了类似的方法,但是从另一个方向进行处理,即获取.urlQueryAllowed字符集(很接近,但不太正确),并取出RFC 3986中标识的保留字符。在Swift 3中:

    /// Returns a percent-escaped string following RFC 3986 for a query string key or value.
    ///
    /// RFC 3986 states that the following characters are "reserved" characters.
    ///
    /// - General Delimiters: ":", "#", "[", "]", "@", "?", "/"
    /// - Sub-Delimiters: "!", "$", "&", "'", "(", ")", "*", "+", ",", ";", "="
    ///
    /// In RFC 3986 - Section 3.4, it states that the "?" and "/" characters should not be escaped to allow
    /// query strings to include a URL. Therefore, all "reserved" characters with the exception of "?" and "/"
    /// should be percent-escaped in the query string.
    ///
    /// - parameter string: The string to be percent-escaped.
    ///
    /// - returns: The percent-escaped string.
    public func escape(_ string: String) -> String {
        let generalDelimitersToEncode = ":#[]@" // does not include "?" or "/" due to RFC 3986 - Section 3.4
        let subDelimitersToEncode = "!$&'()*+,;="
    
        var allowedCharacterSet = CharacterSet.urlQueryAllowed
        allowedCharacterSet.remove(charactersIn: "\(generalDelimitersToEncode)\(subDelimitersToEncode)")
    
        var escaped = ""
    
        //==========================================================================================================
        //
        //  Batching is required for escaping due to an internal bug in iOS 8.1 and 8.2. Encoding more than a few
        //  hundred Chinese characters causes various malloc error crashes. To avoid this issue until iOS 8 is no
        //  longer supported, batching MUST be used for encoding. This introduces roughly a 20% overhead. For more
        //  info, please refer to:
        //
        //      - https://github.com/Alamofire/Alamofire/issues/206
        //
        //==========================================================================================================
        if #available(iOS 8.3, *) {
            escaped = string.addingPercentEncoding(withAllowedCharacters: allowedCharacterSet) ?? string
        } else {
            let batchSize = 50
            var index = string.startIndex
    
            while index != string.endIndex {
                let startIndex = index
                let endIndex = string.index(index, offsetBy: batchSize, limitedBy: string.endIndex) ?? string.endIndex
                let range = startIndex..<endIndex
    
                let substring = string.substring(with: range)
    
                escaped += substring.addingPercentEncoding(withAllowedCharacters: allowedCharacterSet) ?? substring
    
                index = endIndex
            }
        }
    
        return escaped
    }
    
    Run Code Online (Sandbox Code Playgroud)

然后,您可以使用上述代码对请求正文中的键和值进行百分比转义,例如:

let parameters = ["email" : email, "password" : password]
request.httpBody = parameters
    .map { (key, value) in
        let escapedKey = key.addingPercentEncodingForURLQueryValue()!
        let escapedValue = value.addingPercentEncodingForURLQueryValue()!
        return "\(escapedKey)=\(escapedValue)"
    }
    .joined(separator: "&")
    .data(using: .utf8)
Run Code Online (Sandbox Code Playgroud)

对于上述的Swift 2版本,请参阅此答案先前版本