When transmitting data in the context of the HTTP protocol you often need to encode text in a way that does not interfere with special characters used in URLs. This is of importance if you want to put unicode characters into an URL query but also for simple things like constructing a body for a HTTP POST request. A form post also takes the form fields and puts them into the form that you know from an URL: field=text&another=more. That’s what the HTML content type “application/x-www-form-urlencoded” means.
The first thing that jumps out of the documentation when looking for a standard function to achieve such “URL Encoding” is stringByAddingPercentEscapesUsingEncoding. So that is what I was using for encoding the password for my iTunes Connect class which drives MyAppSales. And until now this worked without a hitch until customer #113 who was the first to use a plus character in his password. The poor guy ended up locking his iTunes account. Sorry!
It turns out that + is an anachronistic special character substitution for a space. I would have expected for it to be encoded properly by the above mentioned method as %20, but this is not the case.
This you can verify for yourself by this experiment:
NSString *password = @"Top+Secret. ";
NSString *encoded_normal = [password stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSString *encoded_safer = (NSString *)CFURLCreateStringByAddingPercentEscapes(NULL, (CFStringRef)password, NULL, (CFStringRef)@"!*'();:@&=+$,/?%#[]", kCFStringEncodingUTF8);
// output with %@ otherwise the % escapes cause strange output
NSLog(@"%@", password);
NSLog(@"%@", encoded_normal);
NSLog(@"%@", encoded_safer);
|
You will find that the + does not get encoded by stringByAddingPercentEscapesUsingEncoding. This example also contains a solution for the dilemma. CoreFoundation provides a cousin of the NSString instance method which also allows to specify characters for which you want to forced encoding even though they are deemed safe. So-called “toll free bridging” allows us to simple typecast CFStringRef into NSString and vice versa. This does the trick.
Thanks to Andrew Nicolle who pointed this out to me in completely unrelated circumstances. Your solution has wider reaching consequences than anticipated!
Obviously it’s smart to put the above mentioned method together with all the other NSString helper methods so that you can save yourself unnecessary duplication of code.
NSString+Helpers.h
NSString+Helpers.m
#import "NSString+Helpers.h"
@implementation NSString (Helpers)
#pragma mark Helpers
- (NSString *) stringByUrlEncoding
{
return (NSString *)CFURLCreateStringByAddingPercentEscapes(NULL, (CFStringRef)self, NULL, (CFStringRef)@"!*'();:@&=+$,/?%#[]", kCFStringEncodingUTF8);
}
@end
|
Finally, here is an example of building and sending a HTTP POST that uses this method. If somebody knows of a more elegant way to construct one please let me know. The regular NSURLRequest is a GET and the only way I found that allowed me to change the verb to POST was to use an NSMutableURLRequest instead. This intentionally omits the 4 necessary call-back methods of the NSURLConnectionDelegate protocol for brevity.
// #import for NSString+Helpers.h at the top
NSMutableURLRequest *theRequest=[NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"http://server/post_url"]
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:30.0];
[theRequest setHTTPMethod:@"POST"];
[theRequest addValue:@"application/x-www-form-urlencoded" forHTTPHeaderField: @"Content-Type"];
//create the body
NSMutableData *postBody = [NSMutableData data];
[postBody appendData:[[NSString stringWithFormat:@"name=%@&password=%@",
[username stringByUrlEncoding],
[password stringByUrlEncoding]] dataUsingEncoding:NSUTF8StringEncoding]];
[theRequest setHTTPBody:postBody];
NSURLConnection *theConnection=[[[NSURLConnection alloc] initWithRequest:theRequest delegate:self] autorelease];
|
Coming to think of it, if there really is no smarter way to make an asychronous HTTP POST then maybe I should put all of this into a category for NSURLRequest. But that’s another story.
from http://www.cocoanetics.com/2009/08/url-encoding/
相关推荐
在iOS开发中,读取URL内容是常见的任务,特别是在网络请求和数据获取方面。这个"iPhone读取url内容demo"示例将展示如何利用Swift语言从互联网上的指定URL获取数据。下面我们将深入探讨这一主题。 首先,我们需要...
1. `- (NSString *)stringByAddingPercentEscapesUsingEncoding:(NSStringEncoding)encoding`:这个方法用于对字符串进行URL编码,将非字母数字字符替换为百分号编码。这里的`encoding`参数指定字符串的编码方式,...
request.httpBody = ("token=" + tokenValue()).data(using: String.Encoding.utf8) self.wkWebView.load(request as URLRequest) } ``` 在上面的代码中,我们首先检查当前的 iOS 版本是否大于或等于 11。如果是...
源码中,开发者可能会使用Objective-C的`CFStringTransform`函数或Swift的`String.Encoding`类进行编码转换。 接着,我们来看“通过URL得到网络数据”这一环节。在iOS应用中,通常使用Foundation框架中的`...
let text = String(data: data, encoding: .utf8) print(text!) // 输出:Hello, World! ``` 3. **追加内容**:如果需要向已存在的文件追加内容,可以使用`FileHandle`类: ```swift let fileHandle = ...
NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]; // 使用jsonString } else { NSLog(@"Error serializing JSON: %@", error); } ``` 在iOS开发中,经常需要...
在iOS开发中,特殊字符处理是一项关键任务,尤其是在处理用户输入、存储数据或者网络通信时。Foundation框架和CoreFoundation框架提供了强大的支持来处理这些字符,确保数据的安全性和一致性。下面我们将详细探讨这...
let postData = soapMessage.dataUsingEncoding(NSUTF8StringEncoding)! let request = NSMutableURLRequest(URL: url) request.HTTPMethod = "POST" request.addValue("text/xml", forHTTPHeaderField: "Content-...
在实际项目中,你可能还需要处理URLSchemes,例如使用`UIDocumentInteractionController`来打开或分享文件,或者利用`QLPreviewController`来预览文档。对于更复杂的数据存储,如JSON、SQLite数据库或Core Data,iOS...
let htmlString = try? String(contentsOfFile: htmlPath, encoding: .utf8) webView.loadHTMLString(htmlString ?? "", baseURL: nil) } } } ``` 在这个例子中,我们首先创建了一个UIWebView实例,并将其添加...
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <key>items <key>assets <key>kind ...
try content.write(to: fileURL, atomically: true, encoding: .utf8) print("CSV 文件已成功保存到 \(fileURL.absoluteString)") } catch { print("保存CSV文件时发生错误: \(error)") } } ``` 最后,为了使...
2. **使用URL和FileManager API**:iOS中的文件操作通常通过`FileManager`类来完成,它提供了大量的方法用于读取、写入和管理文件。首先,我们需要使用`FileManager.default.urls(for:in:)`获取沙盒内的文件URL,...
例如,验证邮箱地址的格式或从文本中提取URL。 3. **GIF动画处理** iOS原生不支持GIF动画播放,但有多个第三方库可以解决这个问题。比如`FLAnimatedImage`,它是对`UIImage`的扩展,优化了GIF解码和渲染,性能优秀...
let responseString = String(data: data, encoding: .utf8) // 解析responseString,提取IP地址 } func connectionDidFinishLoading(_ connection: NSURLConnection) { // 请求完成,释放连接资源 } ...
String(contentsOf: logFileURL, encoding: .utf8) { print("日志内容:\(content)") } ``` 通过以上步骤,我们就实现了在iOS应用中将日志写入Document目录的txt文件,并实现了日志追加的功能。这样,每次运行...
let ipString = String(data: data, encoding: .utf8)?.trimmingCharacters(in: .whitespacesAndNewlines) print("IP Address: \(ipString)") return ipString } else if let error = error { print("Error: \...
在iOS开发中,URL编码和解码是处理网络请求时必不可少的部分。URL(统一资源定位符)有时会包含特殊字符,这些字符在HTTP协议中可能具有特殊含义,因此需要进行编码以确保数据的正确传输。本文将详细讲解如何在...
NSString *receText = [[url host] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; NSLog(@"参数:%@ URL:%@",receText, url.absoluteString); return YES; }
String(contentsOf: fileURL).write(to: fileURL, atomically: true, encoding: .utf8) ``` 3. **SQLite数据库** SQLite是一个轻量级的关系型数据库,适用于存储结构化的数据。iOS中的SQLite可以通过`FMDB`等第...