Base64通过HTTP POST丢失数据 (Objective-C)

18

我目前有一个HTTP POST请求和一个Base64编码库,我将图像编码为B64,然后通过POST方法通过HTTP发送它。

我在XCode的控制台输出Base64,复制并粘贴它,它完美地工作。虽然我在数据库中存储的Base64(MongoDB,纯文本文件等)始终在另一端出现损坏。

工作版本(从XCode复制并粘贴):http://dontpanicrabbit.com/api/working.php 损坏版本(来自MongoDB数据库):http://dontpanicrabbit.com/api/grabimage.php

如果您查看源代码,您会注意到它们是相同的,但是在损坏的版本中添加了空格。

我使用的Objective-C代码是:

MyImage.image = [info objectForKey:UIImagePickerControllerOriginalImage];

    NSData *imageData = UIImageJPEGRepresentation(MyImage.image, 0);

    [Base64 initialize];
    NSString *encoded = [Base64 encode:imageData];

    NSString *urlPOST = encoded;
    //NSLog(@"%@",encoded);

    NSString *varyingString1 = @"picture=";
    NSString *varyingString2 = urlPOST;
    NSString *post = [NSString stringWithFormat: @"%@%@", varyingString1, varyingString2];
    NSLog(@"%@", post);
    //NSString *post = @"image=%@",urlPOST;
    NSData *postData = [post dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];

    NSString *postLength = [NSString stringWithFormat:@"%d", [postData length]];

    NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
    [request setURL:[NSURL URLWithString:@"url/api/insertimage.php"]];
    [request setHTTPMethod:@"POST"];
    [request setHTTPBody:postData];
    NSData *returnData = [NSURLConnection sendSynchronousRequest: request returningResponse: nil error: nil];
    NSString *strResult = [[NSString alloc] initWithData:returnData encoding:NSUTF8StringEncoding];

PHP -> MongoDB 存储

<?php
    try {
      // open connection to MongoDB server
      $conn = new Mongo('localhost');

      // access database
      $db = $conn->dablia;

      // access collection
      $collection = $db->images;

      // insert a new document
      $item = array(
        'picture' => $_POST['picture']
      );
      $collection->insert($item);
      echo 'Inserted document with ID: ' . $item['_id'];

      // disconnect from server
      $conn->close();
    } catch (MongoConnectionException $e) {
      die('Error connecting to MongoDB server');
    } catch (MongoException $e) {
      die('Error: ' . $e->getMessage());
    }
?>

输出代码:

<?php
try {
  // open connection to MongoDB server
  $conn = new Mongo('localhost');

  // access database
  $db = $conn->dablia;

  // access collection
  $collection = $db->images;

  // execute query
  // retrieve all documents
  $cursor = $collection->find();

  // iterate through the result set
  // print each document
  foreach ($cursor as $obj) {
    echo '<img src="data:image/jpeg;base64,'.trim($obj['picture']).'">';
  }

  // disconnect from server
  $conn->close();
} catch (MongoConnectionException $e) {
  die('Error connecting to MongoDB server');
} catch (MongoException $e) {
  die('Error: ' . $e->getMessage());
}
?>

我不知道为什么似乎我在POST时出现了损坏的情况?


Base64编码的数据可能包含'+'字符。在x-www-form-urlencoded数据中(我预计您POST的数据是这种格式),接收方知道'+'是空格字符的编码。因此,由于您没有对base64值进行URL编码,任何'+'的实例都会导致接收到的数据损坏。这可能是您正在经历的问题,也可能不是,但您最终会遇到这个问题。 - imaginaryboy
我认为问题出在 PHP 输出时的空格上,我已经比较了两个版本(从转换中直接复制粘贴和 PHP 数据库版本),似乎 PHP 版本的源代码中有空格和换行符,这导致它无法正常工作。我尝试在 echo 周围使用 trim(),但没有效果。 - Jacob Clark
你的 $_POST['picture'] 值与你从 iOS 应用程序记录的值相同吗?另外,如果你认为问题出在 PHP 输出值时,也许你应该在你的问题中包含那段代码? - imaginaryboy
我不确定你是否可以发布(或链接到)正确数据和带有额外空格的数据的示例? - imaginaryboy
已更新帖子并添加了链接 :) - Jacob Clark
显示剩余3条评论
1个回答

45
问题正是我在第一条评论中提出的。也就是说,base64编码数据可以包含“+”字符。在x-www-form-urlencoded数据中,接收方知道“+”是空格字符的编码。因此,由于您没有对base64值进行URL编码,任何“+”的实例都会在接收时导致数据损坏。
当接收和存储数据时,“+”字符会变成“ ”。然后输出该值时,它是无效的base64编码数据。
如果您检查工作示例与非工作示例的源代码,您将看到空格存在于原始Base64编码值中有“+”的位置。您看到的任何换行符都是因为您查看源代码时使用的内容在“ ”处换行。
在您的iOS代码中,您需要正确地对base64编码值进行编码,在您的情况下,您只需要对“+”字符进行百分比编码。
编辑添加,回应评论:
post = [post stringByReplacingOccurrencesOfString:@"+" withString:@"%2B"];

刚刚尝试了一下使用 post = [post stringByReplacingOccurrencesOfString:@"+" withString:@"%"];,现在字符串根本没有存储在Mongo中,尽管XCode在其控制台中输出了它。PHP输出Null,我在VaryString 1和2的连接行下面添加了一行。 - Jacob Clark
我也遇到了同样的问题,现在按照你的指示解决了!非常感谢:D - Shinichi
非常感谢您节省了我的时间!! - Hamzeh Soboh
非常感谢您。 - SURESH SANKE

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接