POST映像到服务器iOS无法正常工作

时间:2014-04-27 01:18:48

标签: ios http post

我正在尝试向我的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);
}

4 个答案:

答案 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-dataHTML5 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中检查请求,以确保请求看起来应该是什么。几点意见:

  1. 绝对是multipart/form-data,而不只是form-data

  2. 您说不是接收JSON响应,而是收到“网站基本页面模板的html页面”。

    对于应该返回JSON以返回HTML页面的页面来说,这是非常不寻常的。如果存在一些阻碍API开发人员代码运行的基本问题(例如基本身份验证错误或URL本身不正确),就会发生这种情况。我敢打赌,如果你告诉你的API开发人员你收到了什么样的HTML回复,他/她可以帮助你诊断出错了。

  3. 与您的直接挑战无关:

    1. 我不建议使用一个本身以破折号开头的边界。我不认为它会导致问题,但是当你用Charles这样的方式调试请求时,它会让你感到困惑。因为您的边界包含四个破折号,所以您将在请求中看到六个破折号。这似乎有点不必要地混淆。

    2. 我很惊讶usernameapi_key是网址的一部分,因为这不安全。您向我们保证您已经确认这是API设计所需要的,但是一旦您立即得到这个问题,您真的应该向API开发人员提出这个主题,因为将身份验证详细信息放在URL中是不明智的。图像数据以及usernameapi_key都应在请求正文中获得自己的“部分”,而不会出现在网址中。

    3. 您真的不希望通过pictureFilePath往返UIImage。只需使用dataWithContentsOfFile并直接获取数据,然后发送即可。 UIImageJPEGRepresentation可能会生成与原始图像不同的有效负载(系数为1.0f,可能比原始文件大,如果小于1.0f,则可能会导致图像质量下降)。除非你有明确的理由通过UIImage进行往返,否则你不应该这样做。

    4. 如果用户用户名或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请求中,则需要百分比转义。

相关问题