我使用以下命令将电子邮件和密码发布到我的服务器(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 规范x-www-form-urlencoded http://www.w3.org/TR/html5/forms.html#application/x-www-form-urlencoded-encoding-algorithm). As the queryItems文档 https://developer.apple.com/documentation/foundation/nsurlcomponents/1407752-queryitems says:
Note
RFC 3986 https://www.ietf.org/rfc/rfc3986.txt指定 URL 的查询组件中哪些字符必须进行百分比编码,但不指定应如何解释这些字符。使用分隔键值对是一种常见约定,但并未由规范标准化。因此,您可能会遇到与遵循此约定的其他实现的互操作性问题。
潜在互操作性问题的一个值得注意的例子是加号 (+
) 字符的处理:
根据 RFC 3986,加号是查询中的有效字符,不需要进行百分比编码。然而,根据W3C 对 URI 寻址的建议 https://www.w3.org/Addressing/URL/4_URI_Recommentations.html,加号被保留作为查询字符串中空格的速记符号(例如,?greeting=hello+world
).
如果您的值可能包含+
特点:
-
您可以构建自己的CharacterSet
要转义的字符然后使用addingPercentEncodingForURLQueryValue
在斯威夫特 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-._~/?")
}
}
-
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 版本,请参阅此答案的先前修订版 https://stackoverflow.com/revisions/35912606/2.
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)