如何在 Swift 中转义 HTTP 参数
Posted
技术标签:
【中文标题】如何在 Swift 中转义 HTTP 参数【英文标题】:How to escape the HTTP params in Swift 【发布时间】:2014-11-26 11:33:59 【问题描述】:我正在尝试向 HTTP 服务器发帖
顺便说一下,这是我的代码:
func sendPostToUrl(url:String, withParams params: [String: String?] )
var request = NSMutableURLRequest(URL: NSURL(string: url)!)
var session = NSURLSession.sharedSession()
request.HTTPMethod = "POST"
var err: NSError?
var bodyData = ""
for (key,value) in params
if (value==nil) continue
let scapedKey = key.stringByAddingPercentEncodingWithAllowedCharacters(
.URLHostAllowedCharacterSet())!
let scapedValue = value!.stringByAddingPercentEncodingWithAllowedCharacters(
.URLHostAllowedCharacterSet())!
bodyData += "\(scapedKey)=\(scapedValue)&"
request.HTTPBody = bodyData.dataUsingEncoding
(NSUTF8StringEncoding, allowLossyConversion: true)
var task = session.dataTaskWithRequest(request,
completionHandler: data, response, error -> Void in
println("Response: \(response)")
let dataString = NSString(data: data, encoding: NSUTF8StringEncoding)
println("Data: \(dataString)")
)
task.resume()
它有效,但并不完美。如果我这样调用函数:
client.sendPostToUrl("http://novagecko.com/tests/test.php",
withParams: ["hello":"world","inject":"param1=value1¶m2=value2"]);
服务器检测到 3 个帖子字段(键为 hello
、inject
和 param2
)而不是 2 个。
如何转义键和值?
我还能做些什么来改进方法吗?
【问题讨论】:
【参考方案1】:如果您可以针对 ios 8(感谢 @Rob),请改用 NSURLComponents
转义您的参数:
import Foundation
func encodeParameters(#params: [String: String]) -> String
var queryItems = map(params) NSURLQueryItem(name:$0, value:$1)
var components = NSURLComponents()
components.queryItems = queryItems
return components.percentEncodedQuery ?? ""
现在encodeParameters(params:["hello":"world","inject":"param1=value1&param2=value2"])
返回hello=world&inject=param1%3Dvalue1%26param2%3Dvalue2
,正如您所期望的那样。
否则,创建可让您正确转义值的字符集的最佳方法是:
var safeCharacterSet = NSCharacterSet.URLQueryAllowedCharacterSet().mutableCopy()
safeCharacterSet.removeCharactersInString("&=")
并查看@rintaro 的回答,以正确使用过滤器/映射来以一种不错的方式执行编码。
【讨论】:
我同意您的字符集似乎复制了percentEncodedQuery
所做的事情,但有一个问题:该字符集让 +
未经转义通过! Web 服务器将+
替换为空格(由x-www-form-urlencoded
规范规定)。 +
应该添加到您的字符中以从安全字符集中删除。我认为 percentEncodedQuery
未能逃脱 +
是值得报告的错误。
好收获。我确实复制了 percentEncodedQuery
所做的事情。
我认为问题在于 NSURLComponents 遵循 RFC3986,它没有说明查询字符串的格式。文档根本没有提到 x-www-form-urlencoded,所以结果可能是预期的......不确定它是否值得出错。如果您确实提交了错误,请在此处粘贴编号!
我非常不同意他们的实现准确地遵循 RFC 3986,其中包括 +
在要进行百分比编码的“保留”字符中,除非“URI 方案明确允许这些字符表示其中的数据组件”(第 2.2 节),至少在查询数据中,+
绝对不是。该 RFC 将 rintaro 的字符集定义为唯一不应该被百分比转义的字符(第 2.3 节)。这都是学术性的:+
肯定需要进行百分比转义,否则服务器将替换为空间。我会提交错误报告。
这绝对是迂腐的,但是 RFC 说在查询部分不必编码的字符是 pchar / "/" / "?"其中 pchar 定义为 unreserved / pct-encoded / sub-delims / ":" / "@",而 subdelims 包括 +(和 &,和 =)。显然 &s 和 =s 被编码在键/值中,否则一切都会中断,但我认为你需要一个额外的规范(可能是 x-www-form-urlencoded)来让你编码 +【参考方案2】:
看来,NSCharacterSet
没有相关设置。
所以,添加这个
extension NSCharacterSet
class func URLUnreservedCharacterSet() -> NSCharacterSet
return self(charactersInString: "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_.~")
然后
var bodyData = ""
var safeCharacterSet = NSCharacterSet.URLUnreservedCharacterSet()
for (key,value) in params
if (value==nil) continue
let scapedKey = key.stringByAddingPercentEncodingWithAllowedCharacters(safeCharacterSet)!
let scapedValue = value!.stringByAddingPercentEncodingWithAllowedCharacters(safeCharacterSet)!
bodyData += "\(scapedKey)=\(scapedValue)&"
按照@Rob 在评论中的建议,这里有一个map
和join
的例子:
let params:[String:String?] = ["fubar":nil, "hello":"world", "inject":"param1=value1¶m2=value2"]
let safeCharacterSet = NSCharacterSet.URLUnreservedCharacterSet()
let pairs = filter(params, $1 != nil).map (key, value) -> String in
let _key = key.stringByAddingPercentEncodingWithAllowedCharacters(safeCharacterSet)!
let _val = value!.stringByAddingPercentEncodingWithAllowedCharacters(safeCharacterSet)!
return _key + "=" + _val
let bodyData = "&".join(pairs)
这样更好,因为结果中没有尾随 &
。
【讨论】:
您可以这样做:var safeCharacterSet = NSCharacterSet.URLQueryAllowedCharacterSet().mutableCopy(); safeCharacterSet.removeCharactersInString("&=")
FWIW,rintaro 的字符集符合 RFC 3986 对“未保留”字符的定义,恕我直言。有关一些参考资料,请参阅 ***.com/a/24888789/1271826。至少,如果您要使用这种removeCharactersInString
方法,请也包含+
字符。以上是关于如何在 Swift 中转义 HTTP 参数的主要内容,如果未能解决你的问题,请参考以下文章
Excel:如何在 excel 中转义逗号以在另一个函数(具有多个参数)内传递一个函数(具有多个参数)
如何为大查询制作类似 java 准备语句的查询或如何在大查询中转义参数