ios http POST(数据和图像):图像未张贴 [英] ios http POST (Data and Image): Image not getting posted

查看:237
本文介绍了ios http POST(数据和图像):图像未张贴的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用以下代码将图像和数据推送到服务器。正在发送数据,但在服务器中未接收到图像。有人可以发现我,如果我的下面的代码中有一个错误,我已经使用:

  NSString * urlString = [[NSString alloc ] initWithString:[NSString stringWithFormat:@%@ action = savesign,MainURL]]; 

//设置表单键和值(在某点 - 使用1个NSDictionary在2个数组之前修改)
NSArray * keys = [[NSArray alloc] initWithObjects:@user ,@poll,nil];
NSArray * vals = [[NSArray alloc] initWithObjects:user,pollid,nil];

//设置请求对象
NSMutableURLRequest * request = [[NSMutableURLRequest alloc] init];
[request setURL:[NSURL URLWithString:urlString]];
[request setHTTPMethod:@POST];

//将内容类型添加到标题。需要使用字符串边界进行数据上传。
NSString * boundary = @0xKhTmLbOuNdArY;
NSString * contentType = [NSString stringWithFormat:@multipart / form-data; boundary =%@,boundary];
[request addValue:contentType forHTTPHeaderField:@Content-Type];

//创建帖子主体
NSMutableData * body = [NSMutableData data];
[body appendData:[[NSString stringWithFormat:@ - %@ \r\\\
,boundary] dataUsingEncoding:NSASCIIStringEncoding]];

//添加(键,值)对(不知道为什么所有的\r和\\\
是必要的...但每个人似乎都有)
for(int i = 0; i <[keys count]; i ++){
[body appendData:[[NSString stringWithFormat:@Content-Disposition:form-data; name = \%@ \\r\\ \\ n\r\\\
,[keys objectAtIndex:i]] dataUsingEncoding:NSASCIIStringEncoding]];
[body appendData:[[NSString stringWithFormat:@%@,[vals objectAtIndex:i]] dataUsingEncoding:NSASCIIStringEncoding]];
[body appendData:[[NSString stringWithFormat:@\r\\\
- %@ \r\\\
,boundary] dataUsingEncoding:NSASCIIStringEncoding]];
}
[bodyappendData:[@Content-Disposition:form-data; name = \image\\r\\\
dataUsingEncoding:NSASCIIStringEncoding]];
[body appendData:[@Content-Type:application / octet-stream\r\\\
\r\\\
dataUsingEncoding:NSASCIIStringEncoding]];
[body appendData:[NSData dataWithContentsOfFile:pngFilePath]];
[body appendData:[[NSString stringWithFormat:@\r\\\
- %@ - \r\\\
,boundary] dataUsingEncoding:NSASCIIStringEncoding]];


NSData * imageData = UIImagePNGRepresentation(_Signfield.image);
[body appendData:[[NSString stringWithFormat:@ - %@ \r\\\
,boundary] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithFormat:@Content-Disposition:form-data; name = \%@ \; filename = \myPngFile.png\\r\ n,_Signfield.image] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[@Content-Type:image / jpeg\r\\\
\r\\\
dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:imageData];
[body appendData:[[NSString stringWithFormat:@\r\\\
] dataUsingEncoding:NSUTF8StringEncoding]];

//将帖子的主体设置为reqeust
[request setHTTPBody:body];

//连接到web
NSData * returnData = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
NSString * returnString = [[NSString alloc] initWithData:returnData encoding:NSUTF8StringEncoding];

NSLog(returnString);

这是来自服务器的响应

  {status:failure,error:[],user:0} 


当我登录并检查数据,但没有图像。

解决方案

当您通过HTTP POST执行文件上传时,通过线路传输的数据如下所示:

  POST / upload HTTP / 1.1 
接受:* / *
接受编码:gzip,deflate,compress
Content-Length:17918
Content-Type:multipart / form-data; boundary = 0xKhTmLbOuNdArY
Host:example.com
User-Agent:HTTPie / 0.7.2

--0xKhTmLbOuNdArY
Content-Disposition:form-data; name =user

Diphin-Das
--0xKhTmLbOuNdArY
Content-Disposition:form-data; name =poll

1
--0xKhTmLbOuNdAry
Content-Disposition:form-data; name =image; filename =myPNGFile.png
Content-Type:image / png

[二进制PNG图像数据未显示]
--0xKhTmLbOuNdArY--

前七行是描述请求到服务器的HTTP头,包括:




  • HTTP请求方法( POST

  • $ c> / upload )

  • HTTP协议版本( HTTP / 1.1

  • 请求正文的长度( Content-Length:17918

  • 请求正文( Content-Type:multipart / form-data; boundary = 0xKhTmLbOuNdArY


$ b b

最后一个很有趣。通过将内容类型设置为 multipart / form-data ,我们可以在请求正文中包含不同数据类型的混合。 boundary 告诉服务器每个表单值在请求正文中是如何分隔的。



请求正文中的表单值使用一个简单的结构描述:

   -  [boundary marker] 
Content-Disposition:form-data; name =[parameter name]
Content-Type:[parameter value MIME type]

[parameter value]

如果参数值是字母数字,但是对于其他数据类型(图像,视频,文档等),Content-Type头是可选的。请求体的结束由终止边界标记来表示,该边界标记是以双连字符为后缀的标准边界标记,例如。 - 0xKhTmLbOuNdArY - 。新行字符(\r\\\
)用于定界内容部分的各个元素。



多部分POST请求中的表单值可以有其他元素。如果您有兴趣,可以在 RFC 2388 中阅读。



为了从Objective-C上传文件,您需要根据上述规范来制作请求主体。我已经从你的问题的代码,并重构它,以正确运行&添加了一些说明。

  NSDictionary * params = @ {@user:user,@poll :pollid}; 
NSData * imageData = UIImagePNGRepresentation(_Signfield.image);

NSString * urlString = [[NSString alloc] initWithString:[NSString stringWithFormat:@%@ action = savesign,MainURL]];

NSMutableURLRequest * request = [[NSMutableURLRequest alloc] init];
[request setURL:[NSURL URLWithString:urlString]];
[request setHTTPMethod:@POST];

NSString * boundary = @0xKhTmLbOuNdAry;
NSString * kNewLine = @\r\\\
;

//注意,setValue用于覆盖任何现有的Content-Type头。
// addValue追加到Content-Type头
NSString * contentType = [NSString stringWithFormat:@multipart / form-data; boundary =%@,boundary];
[request setValue:contentType forHTTPHeaderField:@Content-Type];

NSMutableData * body = [NSMutableData data];

//将字典中的参数添加到请求主体
for(NSString * name in params.allKeys){
NSData * value = [[NSString stringWithFormat:@ %@,params [name]] dataUsingEncoding:NSUTF8StringEncoding];

[body appendData:[[NSString stringWithFormat:@ - %@%@,boundary,kNewLine] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithFormat:@Content-Disposition:form-data; name = \%@ \,name] dataUsingEncoding:NSUTF8StringEncoding]];
//对于简单的数据类型,如文本或数字,没有必要设置内容类型
[body appendData:[[NSString stringWithFormat:@%@%@,kNewLine,kNewLine] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:value];
[body appendData:[kNewLine dataUsingEncoding:NSUTF8StringEncoding]];
}

//将图像添加到请求主体
[body appendData:[[NSString stringWithFormat:@ - %@%@,boundary,kNewLine] dataUsingEncoding NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithFormat:@Content-Disposition:form-data; name = \%@ \; filename = \myPngFile.png \%@,@ image,kNewLine] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithFormat:@Content-Type:image / png] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithFormat:@%@%@',kNewLine,kNewLine] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:imageData];
[body appendData:[kNewLine dataUsingEncoding:NSUTF8StringEncoding]];

//添加终止边界标记以表示我们在请求主体的末尾
[body appendData:[[NSString stringWithFormat:@ - %@ - ,boundary] dataUsingEncoding:NSUTF8StringEncoding]];

[request setHTTPBody:body];

NSData * returnData = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
NSString * returnString = [[NSString alloc] initWithData:returnData encoding:NSUTF8StringEncoding];

NSLog(@%@,returnString);


I used the following code to PUSH an image and data into a server. The data is being sent but the image is not received in the server. Can someone spot me if there is an error in my below code which I have used:

NSString *urlString = [[NSString alloc]initWithString:[NSString stringWithFormat:@"%@action=savesign",MainURL]];

// set up the form keys and values (revise using 1 NSDictionary at some point - neater than 2 arrays)
NSArray *keys = [[NSArray alloc] initWithObjects:@"user",@"poll",nil];
NSArray *vals = [[NSArray alloc] initWithObjects:user,pollid,nil];

// set up the request object
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setURL:[NSURL URLWithString:urlString]];
[request setHTTPMethod:@"POST"];

//Add content-type to Header. Need to use a string boundary for data uploading.
NSString *boundary = @"0xKhTmLbOuNdArY";
NSString *contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@",boundary];
[request addValue:contentType forHTTPHeaderField: @"Content-Type"];

//create the post body
NSMutableData *body = [NSMutableData data];
[body appendData:[[NSString stringWithFormat:@"--%@\r\n",boundary] dataUsingEncoding:NSASCIIStringEncoding]];

//add (key,value) pairs (no idea why all the \r's and \n's are necessary ... but everyone seems to have them)
for (int i=0; i<[keys count]; i++) {
    [body appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"\r\n\r\n",[keys objectAtIndex:i]] dataUsingEncoding:NSASCIIStringEncoding]];
    [body appendData:[[NSString stringWithFormat:@"%@",[vals objectAtIndex:i]] dataUsingEncoding:NSASCIIStringEncoding]];
    [body appendData:[[NSString stringWithFormat:@"\r\n--%@\r\n",boundary] dataUsingEncoding:NSASCIIStringEncoding]];
}
[body appendData:[@"Content-Disposition: form-data; name=\"image\"\r\n" dataUsingEncoding:NSASCIIStringEncoding]];
[body appendData:[@"Content-Type: application/octet-stream\r\n\r\n" dataUsingEncoding:NSASCIIStringEncoding]];
[body appendData:[NSData dataWithContentsOfFile:pngFilePath]];
[body appendData:[[NSString stringWithFormat:@"\r\n--%@--\r\n",boundary] dataUsingEncoding:NSASCIIStringEncoding]];


NSData *imageData = UIImagePNGRepresentation(_Signfield.image);
    [body appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"; filename=\"myPngFile.png\"\r\n", _Signfield.image] dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:[@"Content-Type: image/jpeg\r\n\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:imageData];
    [body appendData:[[NSString stringWithFormat:@"\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];

// set the body of the post to the reqeust
[request setHTTPBody:body];

// make the connection to the web
NSData *returnData = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
NSString *returnString = [[NSString alloc] initWithData:returnData encoding:NSUTF8StringEncoding];

NSLog(returnString);

This is the response from the server

{"status":"failure","error":[],"user":0}

And when I login and check the data is there but not the image.

解决方案

When you perform a file upload via HTTP POST, the data that gets transmitted over the wire looks like this:

POST /upload HTTP/1.1
Accept: */*
Accept-Encoding: gzip, deflate, compress
Content-Length: 17918
Content-Type: multipart/form-data; boundary=0xKhTmLbOuNdArY
Host: example.com
User-Agent: HTTPie/0.7.2

--0xKhTmLbOuNdArY
Content-Disposition: form-data; name="user"

Diphin-Das
--0xKhTmLbOuNdArY
Content-Disposition: form-data; name="poll"

1
--0xKhTmLbOuNdArY
Content-Disposition: form-data; name="image"; filename="myPNGFile.png"
Content-Type: image/png

[Binary PNG image data not shown]
--0xKhTmLbOuNdArY--

The first seven lines are the HTTP headers that describe the request to server, including:

  • The HTTP request method (POST)
  • The resource being requested (/upload)
  • The HTTP protocol version (HTTP/1.1)
  • The length of the request body (Content-Length: 17918)
  • The type of data included in the request body (Content-Type: multipart/form-data; boundary=0xKhTmLbOuNdArY)

That last one is interesting. By setting the content type to multipart/form-data, we're allowed to include a mix of different data types into the request body. The boundary tells the server how each of the form values are separated in the request body.

The form values in the request body are described using a simple structure:

--[boundary marker]
Content-Disposition: form-data; name="[parameter name]"
Content-Type: [parameter value MIME type]

[parameter value]

The Content-Type header is optional if the parameter value is alphanumeric, but for other data types (images, videos, documents, etc.) it's required. The end of request body is signaled by a terminating boundary marker which is a standard boundary marker suffixed with a double-hyphen, e.g. --0xKhTmLbOuNdArY--. New line characters (\r\n) are used to delimit the various elements of the content parts.

There can be other elements to the form values in a multipart POST request. If you're interested, you can read about them in RFC 2388.

In order to upload a file from an Objective-C, you need to craft the request body to that specification outlined above. I've taken the code from your question and refactored it to function correctly & added a few explanatory notes along the way.

NSDictionary *params = @{ @"user": user, @"poll": pollid };
NSData *imageData = UIImagePNGRepresentation(_Signfield.image);

NSString *urlString = [[NSString alloc]initWithString:[NSString stringWithFormat:@"%@action=savesign",MainURL]];

NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setURL:[NSURL URLWithString:urlString]];
[request setHTTPMethod:@"POST"];

NSString *boundary = @"0xKhTmLbOuNdArY";
NSString *kNewLine = @"\r\n";

// Note that setValue is used so as to override any existing Content-Type header.
// addValue appends to the Content-Type header
NSString *contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@",boundary];
[request setValue:contentType forHTTPHeaderField: @"Content-Type"];

NSMutableData *body = [NSMutableData data];

// Add the parameters from the dictionary to the request body
for (NSString *name in params.allKeys) {
    NSData *value = [[NSString stringWithFormat:@"%@", params[name]] dataUsingEncoding:NSUTF8StringEncoding];

    [body appendData:[[NSString stringWithFormat:@"--%@%@", boundary, kNewLine] dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"", name] dataUsingEncoding:NSUTF8StringEncoding]];
    // For simple data types, such as text or numbers, there's no need to set the content type
    [body appendData:[[NSString stringWithFormat:@"%@%@", kNewLine, kNewLine] dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:value];
    [body appendData:[kNewLine dataUsingEncoding:NSUTF8StringEncoding]];
}

// Add the image to the request body
[body appendData:[[NSString stringWithFormat:@"--%@%@", boundary, kNewLine] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"; filename=\"myPngFile.png\"%@", @"image", kNewLine] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithFormat:@"Content-Type: image/png"] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithFormat:@"%@%@", kNewLine, kNewLine] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:imageData];
[body appendData:[kNewLine dataUsingEncoding:NSUTF8StringEncoding]];

// Add the terminating boundary marker to signal that we're at the end of the request body
[body appendData:[[NSString stringWithFormat:@"--%@--", boundary] dataUsingEncoding:NSUTF8StringEncoding]];

[request setHTTPBody:body];

NSData *returnData = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
NSString *returnString = [[NSString alloc] initWithData:returnData encoding:NSUTF8StringEncoding];

NSLog(@"%@", returnString);

这篇关于ios http POST(数据和图像):图像未张贴的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆