我正在尝试向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 个 post 字段(键为 hello
、inject
和 param2
),而不是 2 个。
如何转义键和值?
我还能做些什么来改进方法吗?
如果您可以定位到 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¶m2=value2"])
如您所料返回hello=world&inject=param1%3Dvalue1%26param2%3Dvalue2
。
否则,创建字符集以正确转义值的最佳方法是:
var safeCharacterSet = NSCharacterSet.URLQueryAllowedCharacterSet().mutableCopy()
safeCharacterSet.removeCharactersInString("&=")
并查看@rintaro的答案,以正确使用过滤器/映射以良好的方式执行编码。
似乎,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)
这更好,因为结果中没有尾随&
。