【发布时间】:2014-08-04 00:50:30
【问题描述】:
我正在尝试将图像从 ios 应用上传到 web api 服务。
我正在使用 [data base64EncodedStringWithOptions] 对图像进行编码,然后将其与一些其他数据组合成一个对象,然后使用 NSJSONSerialization 并将其作为“PUT”放置在 NSMutableURLRequest 的主体中,然后使用 NSURLSession 将其发送出去到一个 asp.net web api 服务。
数据到达 Web 服务并使用 JavaScriptSerializer 进行反序列化。然后我使用 Convert.FromBase64String 重新创建图像。然而,Convert.FromBase64String 抛出异常'Base-64 字符数组的长度无效'。图片大小为38988字节。
为了检查这一点,我发送一个包含“a”、“b”、“c”、“”、“=”、“f”(以及各种组合的其他字符)的数组,而不是发送图像。这完美运行,Convert.FromBase64String 不会引发异常。
导致此问题的图像数据可能是什么?
简化的 Xcode
NSString* const Folder = @"SomeFolder";
NSString *fileName = [self getFileName];
NSData *data = UIImageJPEGRepresentation(image, 0.0);
// static char initArray[6] = {'a','b','\0',' ','e','f'}; // if i use this then it works
// NSData* data = [[NSData alloc] initWithBytes:initArray length:6];
NSString* sData = [data base64EncodedStringWithOptions:0];
// set up session
NSError *error;
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration];
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"<service url>/api/Documents/PutDoc/%@", id]];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
NSDictionary *mapData = [[NSDictionary alloc] initWithObjectsAndKeys:Folder, @"folder", fileName, @"fileName", sData, @"sImage", nil];
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:mapData options:0 error:&error];
NSMutableData *postData = (NSMutableData*)[@"=" dataUsingEncoding:NSUTF8StringEncoding];
[postData appendData:jsonData];
[request setHTTPBody:postData];
[request setHTTPMethod:@"PUT"];
[request addValue:@"application/x-www-form-urlencoded; charset=utf-8" forHTTPHeaderField:@"Content-Type"];
[request addValue:@"*/*" forHTTPHeaderField:@"Accept"];
// send request
NSURLSessionDataTask *postDataTask = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
dispatch_async(dispatch_get_main_queue(), ^{
NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*)response;
if ([httpResponse statusCode] == 200) {
NSString* msg = [NSString stringWithFormat: @"Document Saved to server"];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Document Saved" message:msg delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil, nil];
[alert show];
} else {
NSDictionary* dic = [httpResponse allHeaderFields];
NSString* msg = [NSString stringWithFormat: @"Server Error. Code: %d", [httpResponse statusCode]];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Document Not Saved" message:msg delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil, nil];
[alert show];
}
});
}];
web api c# 代码(简体)
JavaScriptSerializer js = new JavaScriptSerializer();
Document doc = (Document)js.Deserialize<Document>(value);
byte[] img;
try {
img = Convert.FromBase64String(doc.sImage);
} catch (Exception e) {
// this is where the 'invalid length' exception is throw
MyLib.LogIt(string.Format("Error converting: {0}", e.Message));
throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.InternalServerError) {
Content = new StringContent("Could not convert image to binary"),
ReasonPhrase = "Conversion Error"
});
}
..
【问题讨论】:
-
跨平台字符问题可能是罪魁祸首。尝试通过虚拟应用程序发布到您的 api,看看它是否可以毫无问题地接受来自 Windows 的编码数据。
-
另一个考虑因素:原始 base64 要求每 72 个字符一个 CRLF。当您的解码器需要它们时,也许您的编码器没有添加它们。通常这可以通过选项来设置。检查编码器/解码器选项。注意:您的测试可能有效,因为它小于 72 字节。
-
好的,经过多次测试,我发现问题是编码图像中的“+”字符被更改为空格。我天真地认为这不会发生,因为我将数据放在 PUT 的正文中。我很困惑为什么错误是“非法长度”而不是“格式不正确”或类似的。即使它非常难看,我的解决方案是在 Web 服务端用 + 字符替换所有空格,这适用于迄今为止的所有图像。我知道有更好的选择(例如 stringByAddingPercentEscapesUsingEncoding),但我仍然不确定能匹配两端的解决方案。
标签: c# ios asp.net web-services