我正在使用以下内容将电子邮件和密码发布到我的服务器(PHP脚本).我遇到的问题是密码包含一个特殊的字符(特别是&符号),它似乎被剥离了.我认为因为它认为它的分离变量被传递了.如何在不剥离它的情况下传递这个字符?
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)
解决方法:
你应该警惕使用NSURLComponents,因为NSURLQueryItem可以百分之百地逃避有问题的字符,&,它不会逃避字符(PHP将解释为符合W3C Specification for x-www-form-urlencoded
的空格).正如the queryItems
documentation所说:
Note
07002 specifies which characters must be percent-encoded in the query component of a URL, but not how those characters should be interpreted. The use of delimited key-value pairs is a common convention, but isn’t standardized by a specification. Therefore, you may encounter interoperability problems with other implementations that follow this convention.
One notable example of potential interoperability problems is how the plus sign (
+
) character is handled:According to RFC 3986, the plus sign is a valid character within a query, and doesn’t need to be percent-encoded. However, according to the 07003, the plus sign is reserved as shorthand notation for a space within a query string (for example,
?greeting=hello+world
).
如果您的值可能包含一个字符,这会为您自己添加到URL查询中的值留下一些替代值:
>您可以构建自己的要转义的CharacterSet字符集,然后在Swift 3中使用addsPercentEncodingForURLQueryValue:
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-._~/?")
}
}
> 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
}
然后,您可以使用上面的百分比来转义键和请求正文中的值,例如:
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)
对于上面的Swift 2演绎,请参阅previous revision of this answer.