Percent Endcoding với Swift
Vấn đề Endcode phát sinh trong dự án của team mình đó là việc phải Endcode URL khi gửi lên WebAPI của khách hàng. Ban đầu team sử dụng hàm endcode mặc định trong IOS và Android, tuy nhiên output của Endcode không thỏa mãn yêu cầu khách hàng. Với yêu cầu của khách hàng thì URL sau khi được encode ...
Vấn đề Endcode phát sinh trong dự án của team mình đó là việc phải Endcode URL khi gửi lên WebAPI của khách hàng. Ban đầu team sử dụng hàm endcode mặc định trong IOS và Android, tuy nhiên output của Endcode không thỏa mãn yêu cầu khách hàng. Với yêu cầu của khách hàng thì URL sau khi được encode thì không được chứa các ký tự đặc biệt nữa. Sau họ gửi cho một trang web về cách endcode theo chuẩn RFC3986 thì team mới tìm hiểu và thấy rằng Percent Endcoding thích hợp nhất để endcode theo đúng yêu cầu khách hàng (hehe)
VD về yêu cầu endcode của KH như sau:
"q=" + uriEncode("a") // => "q=a" "q=" + uriEncode("a b") // => "q=a%20b" "q=" + uriEncode("あ") // => "q=%E3%81%82"
stringByAddingPercentEscapesUsingEncoding
Đây là hàm đầu tiên team sử dụng thử để xem kq có ổn không
func uriEncode(str: String) -> String { return str.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)! }
Những tưởng với cách trên thì encode ngon lành cành đào. Nhưng kết quả khi endcode ra thì vẫn không chuẩn. Vì theo chuẩn RFC3986 thì kể cả các ký tự đặc biệt cũng phải được endcode. Mà kết quả của hàm trên xuất ra thì:
"q=" + uriEncode("=") // => "q==" "q=" + uriEncode("&") // => "q=&"
stringByAddingPercentEncodingWithAllowedCharacters
Tuy nhiên thì từ IOS7 trở lên chúng ta có thể sử dụng API này (honho)
func uriEncode(str: String) -> String { return str.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.alphanumericCharacterSet())! }
Function trên sẽ encode tất cả các ký tự đầu vào theo kiểu Percent Encoding trừ các ký tự được cho phép ở trong ngoặc. Do đó đây có vẻ là phương pháp chuẩn nhất để endcode theo yêu cầu của khách hàng:
"q=" + uriEncode("=") // => "q=%3D" "q=" + uriEncode("&") // => "q=%26" "q=" + uriEncode("-") // => "q=%2D" "q=" + uriEncode("_") // => "q=%5F"
Tuy nhiên Mặc dù phương pháp này thoả mãn yêu cầu của Khách hàng. Nhưng theo chuẩn RFC3986 thì encode vẫn chưa chuẩn. Bởi vì theo chuẩn đó , ngoài các ký tự anphalbet ra có 4 ký tự # nữa cũng không cần phải endcode đó là "-._~"
URLQueryAllowedCharacterSet
Function NSCharacterSet.URLQueryAllowedCharacterSet được sử dụng để thử giải quyết bài toán này, tuy nhiên kết quả trả ra thì hoàn toàn không phù hợp:
// これは駄目なコード func uriEncode(str: String) -> String { return str.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.URLQueryAllowedCharacterSet())! }
uriEncode("!*'();:@&=+$,/?%#[]-._~ ") // => "!*'();:@&=+$,/?%25%23%5B%5D-._~%20"
Mặc dù 4 ký tự trên đã ko encode nhưng kèm theo đó là một loạt ký tự # nữa đó là !*'();:@&=+$,/?(khoc)
Cuối cùng để đạt được kết quả endcoding theo chuẩn RFC3986 thì ngoài việc sử dụng hàm stringByAddingPercentEncodingWithAllowedCharacters để endcode, chúng ta cần tách biến AllowedCharacter trong ngoặc ra trước và add thêm 4 ký tự trên vào -> rất là đơn giản mà mãi mới nghĩ ra