如何在 Swift 中编码 URL

这是我的 URL

问题是,没有将 address字段追加到 urlpath

有人知道为什么吗?

var address:string
address = "American Tourister, Abids Road, Bogulkunta, Hyderabad, Andhra Pradesh, India"
let urlpath = NSString(format: "http://maps.googleapis.com/maps/api/geocode/json?address="+"\(address)")
161378 次浏览

Swift 4.2

var urlString = originalString.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)

Swift 3.0

var address = "American Tourister, Abids Road, Bogulkunta, Hyderabad, Andhra Pradesh, India"
let escapedAddress = address.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryAllowed)
let urlpath = String(format: "http://maps.googleapis.com/maps/api/geocode/json?address=\(escapedAddress)")

使用 stringByAddingPercentEncodingWithAllowedCharacters:

var escapedAddress = address.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.URLQueryAllowedCharacterSet())

在 iOS 9和 OS X v10.11中使用 stringByAddingPercentEscapesUsingEncoding: < em > 弃用

var address = "American Tourister, Abids Road, Bogulkunta, Hyderabad, Andhra Pradesh, India"
var escapedAddress = address.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)
let urlpath = NSString(format: "http://maps.googleapis.com/maps/api/geocode/json?address=\(escapedAddress)")

如果您要添加到 URL 中的值可能具有保留字符(如 RFC 3986第2节所定义的) ,那么您可能需要改进您的百分比转义。值得注意的是,虽然 &+是 URL 中的有效字符,但是它们在 URL 查询参数值中是无效的(因为 &用作查询参数之间的分隔符,这会提前终止您的值,而 +被转换为空格字符)。不幸的是,标准的百分比转义没有转义那些分隔符。

因此,您可能希望对不在 RFC3986无保留字符列表中的所有字符进行百分比转义:

在 URI 中允许但没有保留的字符 这些包括大写和小写 字母,十进制数字,连字符,句号,下划线和波浪线。

unreserved  = ALPHA / DIGIT / "-" / "." / "_" / "~"

后来,在3.4节中,RFC 进一步考虑将 ?/添加到查询中允许的字符列表中:

斜杠(“/”)和问号(“ ?”)可能表示数据 在查询组件中。请注意,一些旧的,错误的 实现可能无法正确处理这些数据,当它被用作 相对引用的基 URI (5.1节) ,显然 因为它们无法区分查询数据和路径数据 寻找分层分隔符。但是,作为查询组件 经常用于携带识别信息的形式 “ key = value”对和一个常用的值是对 另一个 URI,有时为了易用性,最好避免百分比- 编码这些字符。

现在,通常使用 URLComponents来转义查询值的百分比:

var address = "American Tourister, Abids Road, Bogulkunta, Hyderabad, Andhra Pradesh, India"
var components = URLComponents(string: "http://maps.googleapis.com/maps/api/geocode/json")!
components.queryItems = [URLQueryItem(name: "address", value: address)]
let url = components.url!

顺便说一下,虽然在前面提到的 RFC 中没有考虑到这一点,但是 W3C HTML 规范中的 第5.2节,URL 编码的表单数据指出,application/x-www-form-urlencoded请求也应该用 +字符替换空格字符(并且在字符中包含不应该转义的星号)。而且,不幸的是,URLComponents不会正确地百分比转义它,所以苹果建议你在检索 URLComponents对象的 url属性之前手动百分比转义它:

// configure `components` as shown above, and then:


components.percentEncodedQuery = components.percentEncodedQuery?.replacingOccurrences(of: "+", with: "%2B")
let url = components.url!

对于 Swift 2的表演,我手动完成所有这些百分比的转义,参见 这个答案的上一次修订

Swift 2.0

let needsLove = "string needin some URL love"
let safeURL = needsLove.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.URLQueryAllowedCharacterSet())!

有用的编程技巧和技巧

URLQueryAllowedCharacterSet不应该用于查询参数的 URL 编码,因为这个字符集包括 &?/等等,它们在 URL 查询中充当分隔符,例如。

/?paramname=paramvalue&paramname=paramvalue

这些字符在整个 URL 查询中是允许的,但在参数值中不允许。

RFC3986 特别提到了 毫无保留字符,它们与允许的字符不同:

2.3无保留字符

在 URI 中允许但没有保留的字符
这些包括大写和小写 字母,十进制数字,连字符,句号,下划线和波浪线。

  unreserved  = ALPHA / DIGIT / "-" / "." / "_" / "~"

因此:

extension String {
var URLEncoded:String {


let unreservedChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~"
let unreservedCharsSet: CharacterSet = CharacterSet(charactersIn: unreservedChars)
let encodedString = self.addingPercentEncoding(withAllowedCharacters: unreservedCharsSet)!
return encodedString
}
}

上面的代码不调用 alphanumericCharacterSet,因为它返回的字符集非常大(103806个字符)。而且考虑到有多少 Unicode 字符 alphanumericCharacterSet允许,使用它的目的 URL 编码将是完全错误的。

用法:

let URLEncodedString = myString.URLEncoded

在 Mac OS 10.9 Maverics 和 iOS 7中引入了 NSURLComponents,它以一种非常方便的方式处理不同 URL 部分的编码。

NSULComponent 类是一个用于解析 URL 的类 基于 RFC3986,并从它们的组成部分构造 URL。 它的行为与 NSURL 类略有不同,后者符合 但是,您可以很容易地基于 URL 组件对象的内容,反之亦然。

let address = "American Tourister, Abids Road, Bogulkunta, Hyderabad, Andhra Pradesh, India"


let components = NSURLComponents(string: "http://maps.googleapis.com/maps/api/geocode/json")!
// create a query item key=value
let queryItem = NSURLQueryItem(name: "address", value: address)
// add the query item to the URL, NSURLComponents takes care of adding the question mark.
components.queryItems = [queryItem]
// get the properly percent encoded string
let urlpath = components.string!
print(urlpath)

在我的例子中,最后一个组件是非拉丁字符,我在 Swift 2.2中执行了以下操作:

extension String {
func encodeUTF8() -> String? {
//If I can create an NSURL out of the string nothing is wrong with it
if let _ = NSURL(string: self) {


return self
}


//Get the last component from the string this will return subSequence
let optionalLastComponent = self.characters.split { $0 == "/" }.last




if let lastComponent = optionalLastComponent {


//Get the string from the sub sequence by mapping the characters to [String] then reduce the array to String
let lastComponentAsString = lastComponent.map { String($0) }.reduce("", combine: +)




//Get the range of the last component
if let rangeOfLastComponent = self.rangeOfString(lastComponentAsString) {
//Get the string without its last component
let stringWithoutLastComponent = self.substringToIndex(rangeOfLastComponent.startIndex)




//Encode the last component
if let lastComponentEncoded = lastComponentAsString.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.alphanumericCharacterSet()) {




//Finally append the original string (without its last component) to the encoded part (encoded last component)
let encodedString = stringWithoutLastComponent + lastComponentEncoded


//Return the string (original string/encoded string)
return encodedString
}
}
}


return nil;
}
}

补充一下布莱恩 · 陈(Bryan Chen)上面的回答:

只是为了防止其他人得到类似于 Alamofire 的东西:

错误: Alamofire 是用优化步进编译的 奇怪的是,变量可能不可用。

这不是一个描述性的错误。我是在构建谷歌地理服务的 URL 时得到这个错误的。我在 URL 的末尾附加了一个街道地址,但没有首先对街道地址本身进行编码。 我用布莱恩 · 陈的方法解决了这个问题:

var streetAdress = "123 fake street, new york, ny"
var escapedStreetAddress = streetAddress.stringByAddingPercentEncodingWithAllowedCharacters(.URLHostAllowedCharacterSet())
let url = "\(self.baseUrl)&address=\(escapedAddress!)"

这为我修正了它! 它不喜欢的地址有空格和逗号等。

希望这能帮到别人!

斯威夫特3:

let escapedString = originalString.addingPercentEncoding(withAllowedCharacters:NSCharacterSet.urlQueryAllowed)

XCODE 8 SWIFT 3.0

来自格鲁斯威夫特

从字符串创建 URL 是一个漏洞雷区。只是错过了一个/或意外的 URL 编码?你的 API 调用将会失败,你的应用程序将不会显示任何数据(如果你没有预料到这种可能性,甚至会崩溃)。自从 iOS8以来,有一种更好的方法来构建使用 ABC0和 NSURLQueryItems的 URL

func createURLWithComponents() -> URL? {
var urlComponents = URLComponents()
urlComponents.scheme = "http"
urlComponents.host = "maps.googleapis.com"
urlComponents.path = "/maps/api/geocode/json"


let addressQuery = URLQueryItem(name: "address", value: "American Tourister, Abids Road, Bogulkunta, Hyderabad, Andhra Pradesh, India")
urlComponents.queryItems = [addressQuery]


return urlComponents.url
}

下面是使用 guard语句访问 url 的代码。

guard let url = createURLWithComponents() else {
print("invalid URL")
return nil
}
print(url)

输出:

http://maps.googleapis.com/maps/api/geocode/json?address=American%20Tourister,%20Abids%20Road,%20Bogulkunta,%20Hyderabad,%20Andhra%20Pradesh,%20India

延伸阅读: 使用 NSULComponent 和 NSULQueryItems 构建 URL

刚刚完成了 Desmond Hume 的回答,为 RFC 3986无保留字符有效编码函数扩展了 String 类(如果您正在编码查询 FORM 参数,则需要这个函数) :

Swift 3

extension String {


var RFC3986UnreservedEncoded:String {
let unreservedChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~"
let unreservedCharsSet: CharacterSet = CharacterSet(charactersIn: unreservedChars)
let encodedString: String = self.addingPercentEncoding(withAllowedCharacters: unreservedCharsSet)!
return encodedString
}
}

更新为 Swift 3:

var escapedAddress = address.addingPercentEncoding(
withAllowedCharacters: CharacterSet.urlQueryAllowed)

Swift 4.1

根据需要的选项(urlQueryAlallow)创建“字符集”。然后删除不需要的附加字符(+ &)。然后将该字符集传递给“ addingPercentEncoding”。

var address = "American Tourister, Abids Road, Bogulkunta, Hyderabad, Andhra Pradesh, India"
var queryCharSet = NSCharacterSet.urlQueryAllowed
queryCharSet.remove(charactersIn: "+&")
let escapedAddress = address.addingPercentEncoding(withAllowedCharacters: queryCharSet)!
let urlpath = String(format: "http://maps.googleapis.com/maps/api/geocode/json?address=\(escapedAddress)")

我需要用 ISO-8859-1对参数进行编码,因此 addingPercentEncoding ()方法不适合我。 我自己在 Swift 4中提出了一个解决方案:

extension String {


// Url percent encoding according to RFC3986 specifications
// https://tools.ietf.org/html/rfc3986#section-2.1
func urlPercentEncoded(withAllowedCharacters allowedCharacters:
CharacterSet, encoding: String.Encoding) -> String {
var returnStr = ""


// Compute each char seperatly
for char in self {
let charStr = String(char)
let charScalar = charStr.unicodeScalars[charStr.unicodeScalars.startIndex]
if allowedCharacters.contains(charScalar) == false,
let bytesOfChar = charStr.data(using: encoding) {
// Get the hexStr of every notAllowed-char-byte and put a % infront of it, append the result to the returnString
for byte in bytesOfChar {
returnStr += "%" + String(format: "%02hhX", byte as CVarArg)
}
} else {
returnStr += charStr
}
}


return returnStr
}


}

用法:

"aouäöü!".urlPercentEncoded(withAllowedCharacters: .urlQueryAllowed,
encoding: .isoLatin1)
// Results in -> "aou%E4%F6%FC!"