我正在尝试向我的ipad上的iOS服务器发送帖子请求。我已经关注并尝试了多个示例,但我仍然无法使其正常运行。 post请求总是以200状态代码和HTML页面响应,但它应该根据API和API的创建者使用json进行响应。我已经获得了一个有效的示例POST请求。以下是我用来尝试发送照片的功能。
-(IBAction)testSendPhoto:(id)sender
{
NSString *docDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSMutableArray * currentFormPictures = [NSMutableArray arrayWithArray:appDelegate.pictures[appDelegate.currentForm]];
NSString * pictureFilePath = currentFormPictures[0];
NSLog(@"Sending picture:%@", pictureFilePath);
NSString *filename =[pictureFilePath stringByReplacingOccurrencesOfString:[docDir stringByAppendingString:@"/"] withString:@""];
UIImage * pictureFile = [[UIImage alloc] initWithContentsOfFile:pictureFilePath];
NSData *imageData = UIImageJPEGRepresentation(pictureFile, 1.0f);
NSMutableString * urlString = [NSMutableString stringWithString:@"http://urlForSite.com/?format=json"];
[urlString appendString:@"&username="];
[urlString appendString:appDelegate.username];
[urlString appendString:@"&api_key="];
[urlString appendString:appDelegate.apikey];
NSURL *url = [NSURL URLWithString:urlString];
NSLog(@"Sending it to URL: %@", urlString);
NSMutableURLRequest * request= [[NSMutableURLRequest alloc] init];
[request setURL:url];
[request setHTTPMethod:@"POST"];
NSString *boundary = @"----WebKitFormBoundaryE19zNvXGzXaLvS5C";
NSString *contentType = [NSString stringWithFormat:@"form-data; boundary=%@",boundary];
[request setValue:contentType forHTTPHeaderField: @"Content-Type"];
NSMutableData *postbody = [NSMutableData data];
[postbody appendData:[[NSString stringWithFormat:@"\r\n--%@\r\n",boundary] dataUsingEncoding:NSUTF8StringEncoding]];
[postbody appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"file\"; filename=\"%@\"\r\n", filename] dataUsingEncoding:NSUTF8StringEncoding]];
[postbody appendData:[[NSString stringWithString:@"Content-Type: image/jpeg\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
NSLog(@"Post Body:%@", [[NSString alloc] initWithData:postbody encoding:NSUTF8StringEncoding]);
[postbody appendData:imageData];
[postbody appendData:[[NSString stringWithFormat:@"\r\n--%@--\r\n",boundary] dataUsingEncoding:NSUTF8StringEncoding]];
[request setHTTPBody:postbody];
//NSString *postLength = [NSString stringWithFormat:@"%lu", (unsigned long)[postbody length]];
//[request setValue:postLength forHTTPHeaderField:@"Content-Length"];
connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
}
API创建者提供的工作示例:
POST /warehouse/apiTempFileUploader/?format=json&username=admin&api_key=c67332f5596301f598c1807a6767a048ed1d17d9 HTTP/1.1
Host: localhost:8001
Cache-Control: no-cache
----WebKitFormBoundaryE19zNvXGzXaLvS5C
Content-Disposition: form-data; name="file"; filename="GPSEXIF.jpg"
Content-Type: image/jpeg
----WebKitFormBoundaryE19zNvXGzXaLvS5C
我也用过
NSString *contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@",boundary];
作为内容类型,但仍然没有运气。我已经根据API创建者的建议删除了标题而没有运气
- 使用didReceiveResponse,didReceiveData和connectionDidFinishLoading进行更新
(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
responseData = [NSMutableData data];
NSLog(@"Response from connection: %@", [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding]);
NSDictionary * headers = [(NSHTTPURLResponse *)response allHeaderFields];
statusCode = (int)[(NSHTTPURLResponse *)response statusCode];
NSLog(@"headers: %@", headers);
NSLog(@"Status code: %d", statusCode);
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[responseData appendData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSString * responseJson = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
NSDictionary *JSON = [NSJSONSerialization JSONObjectWithData: [responseJson dataUsingEncoding:NSUTF8StringEncoding]
options: NSJSONReadingMutableContainers
error: nil];
NSLog(@"JSon: %@", JSON);
NSLog(@"response data - %@", responseJson);
}
答案 0 :(得分:0)
NSString *contentType = [NSString stringWithFormat:@"form-data; boundary=%@",boundary];
[request setValue:contentType forHTTPHeaderField: @"Content-Type"];
应为@"multipart/form-data; boundary=%@"
。
NSString *contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@",boundary];
[request setValue:contentType forHTTPHeaderField: @"Content-Type"];
更新
我看到了您的新更新。您必须包含multipart/form-data
的内容类型。
请参阅multipart/form-data和HTML5 Specification > Forms > multipart/form-data。
更新2
我不确定您更改了多少网址,但在提供的代码中,您没有路径。
NSMutableString * urlString = [NSMutableString stringWithString:@"http://urlForSite.com/?format=json"];
样本中的路径为/warehouse/apiTempFileUploader/
。
你试过了吗?
NSMutableString * urlString = [NSMutableString stringWithString:@"http://urlForSite.com/warehouse/apiTempFileUploader/?format=json"];
答案 1 :(得分:0)
此外,您可能需要添加
[request setValue:@"application/json" forHTTPHeaderField:@"Accept"];
告诉服务器您正在接受JSON响应。
答案 2 :(得分:0)
您的请求的主要部分绝对应该是" multipart / form-data",而不仅仅是" form-data"。
此外,如果在文件的零件中再添加一个标题,将会有所帮助。这个标题是: 内容传输编码:二进制
最后一次观察,你的代码几乎是完美的。您下面的HTTP示例不正确。边界应该有一个" - "每个部分开头的前缀和另外一个" - "请求结尾处的后缀。
我最近写了一篇文章,仅仅是为了你想做什么。 Check it out,这可能会有所帮助。
答案 3 :(得分:0)
我建议在Charles中检查请求,以确保请求看起来应该是什么。几点意见:
绝对是multipart/form-data
,而不只是form-data
。
您说不是接收JSON响应,而是收到“网站基本页面模板的html页面”。
对于应该返回JSON以返回HTML页面的页面来说,这是非常不寻常的。如果存在一些阻碍API开发人员代码运行的基本问题(例如基本身份验证错误或URL本身不正确),就会发生这种情况。我敢打赌,如果你告诉你的API开发人员你收到了什么样的HTML回复,他/她可以帮助你诊断出错了。
与您的直接挑战无关:
我不建议使用一个本身以破折号开头的边界。我不认为它会导致问题,但是当你用Charles这样的方式调试请求时,它会让你感到困惑。因为您的边界包含四个破折号,所以您将在请求中看到六个破折号。这似乎有点不必要地混淆。
我很惊讶username
和api_key
是网址的一部分,因为这不安全。您向我们保证您已经确认这是API设计所需要的,但是一旦您立即得到这个问题,您真的应该向API开发人员提出这个主题,因为将身份验证详细信息放在URL中是不明智的。图像数据以及username
和api_key
都应在请求正文中获得自己的“部分”,而不会出现在网址中。
您真的不希望通过pictureFilePath
往返UIImage
。只需使用dataWithContentsOfFile
并直接获取数据,然后发送即可。 UIImageJPEGRepresentation
可能会生成与原始图像不同的有效负载(系数为1.0f,可能比原始文件大,如果小于1.0f
,则可能会导致图像质量下降)。除非你有明确的理由通过UIImage
进行往返,否则你不应该这样做。
如果用户用户名或api密钥有可能包含保留字符(例如+
或&
或空格),则在添加之前,您确实需要百分之百地逃避这些值他们到你的URL。请注意,请勿使用stringByAddingPercentEscapesUsingEncoding
,而应使用CFURLCreateStringByAddingPercentEscapes
:
/** Percent escape string
*
* Note, this does not use `stringByAddingPercentEscapesUsingEncoding`, because
* that that will not percent escape some critical reserved characters (notably
* `&` and `+`). This uses `CFURLCreateStringByAddingPercentEscapes`, instead.
*/
- (NSString *)percentEscapeString:(NSString *)string
{
NSString *result = CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault,
(CFStringRef)string,
(CFStringRef)@" ",
(CFStringRef)@":/?@!$&'()*+,;=",
kCFStringEncodingUTF8));
return [result stringByReplacingOccurrencesOfString:@" " withString:@"+"];
}
如果在multipart/form-data
请求中指定了值,则无需这样做,但如果在网址中或在application/x-www-form-urlencoded
请求中,则需要百分比转义。