【问题标题】:Upload image to server as multipart file in ios 7在 ios 7 中将图像作为多部分文件上传到服务器
【发布时间】:2015-01-29 12:01:01
【问题描述】:

在我的 ios 7 应用程序中,我正在尝试将图像及其属性上传到我的服务器。我想传递 4 个值 x、y、w、h,其中 w 和 h 是宽度和高度,x 和 y 是 0。我通过多部分文件上传使用了图像上传的确切格式。但我的服务器显示“输入错误”错误。我花了两天时间解决同样的问题并尝试了很多东西。但它们没有奏效。我正在关注下面给出的我们工作的 android 代码。我还附上了我的 ios 7 代码。

请有人指出我的代码有什么问题或我缺少什么。感谢您的回复。

安卓代码:

public class OWBImageUpload implements Runnable{

    URL connectURL;
    String responseString;
    String Title;
    String Description;
    byte[ ] dataToServer;
    FileInputStream fileInputStream = null;
    String urlString = "https://stage.oneworkbook.com/owb/attachments/photos";
    String token = "";

    public OWBImageUpload(String t, String vTitle, String vDesc){
            try{
                token = t;
                connectURL = new URL(urlString);
                Title= vTitle;
                Description = vDesc;
            }catch(Exception ex){
                Log.i("HttpFileUpload","URL Malformatted");
            }
    }

    public void uploadPhoto(FileInputStream fStream){
            fileInputStream = fStream;
            upload();
    }

    public void upload(){
            String iFileName = Title;
            String lineEnd = "\r\n";
            String twoHyphens = "--";
            String boundary = "*****";
            String Tag="fSnd";

            try
            {
                    Log.e(Tag,"Starting Http File Sending to URL");

                    // Open a HTTP connection to the URL
                    HttpURLConnection conn = (HttpURLConnection)connectURL.openConnection();
                    conn.setRequestProperty(OWBConstants.OWB_TOKEN_AUTH, token);
                    conn.setRequestProperty(OWBConstants.CLIENT_ID, OWBConstants.ANDROID_CLIENT_ID);
                    conn.setRequestProperty(OWBConstants.CLIENT_SECRET, OWBConstants.ANDROID_CLIENT_SECRET);

                    // Allow Inputs
                    conn.setDoInput(true);

                    // Allow Outputs
                    conn.setDoOutput(true);

                    // Don't use a cached copy.
                    conn.setUseCaches(false);

                    // Use a post method.
                    conn.setRequestMethod("POST");

                    conn.setRequestProperty("Connection", "Keep-Alive");

                    conn.setRequestProperty("Content-Type", "multipart/form-data;boundary="+boundary);

                    DataOutputStream dos = new DataOutputStream(conn.getOutputStream());


                    dos.writeBytes(twoHyphens + boundary + lineEnd);
                    dos.writeBytes("Content-Disposition: form-data; name=\"x\""+ lineEnd);
                    dos.writeBytes(lineEnd);
                    dos.writeBytes("0");
                    dos.writeBytes(lineEnd);
                    dos.writeBytes(twoHyphens + boundary + lineEnd);

                    dos.writeBytes(twoHyphens + boundary + lineEnd);
                    dos.writeBytes("Content-Disposition: form-data; name=\"y\""+ lineEnd);
                    dos.writeBytes(lineEnd);
                    dos.writeBytes("0");
                    dos.writeBytes(lineEnd);
                    dos.writeBytes(twoHyphens + boundary + lineEnd);

                    dos.writeBytes(twoHyphens + boundary + lineEnd);
                    dos.writeBytes("Content-Disposition: form-data; name=\"w\""+ lineEnd);
                    dos.writeBytes(lineEnd);
                    dos.writeBytes("1400");
                    dos.writeBytes(lineEnd);
                    dos.writeBytes(twoHyphens + boundary + lineEnd);

                    dos.writeBytes(twoHyphens + boundary + lineEnd);
                    dos.writeBytes("Content-Disposition: form-data; name=\"h\""+ lineEnd);
                    dos.writeBytes(lineEnd);
                    dos.writeBytes("1400");
                    dos.writeBytes(lineEnd);
                    dos.writeBytes(twoHyphens + boundary + lineEnd);

                    dos.writeBytes("Content-Disposition: form-data; name=\"file\";filename=\"" + iFileName +"\"" + lineEnd);
                    dos.writeBytes(lineEnd);

                    // create a buffer of maximum size
                    int bytesAvailable = fileInputStream.available();

                    int maxBufferSize = 1024;
                    int bufferSize = Math.min(bytesAvailable, maxBufferSize);
                    byte[ ] buffer = new byte[bufferSize];

                    // read file and write it into form...
                    int bytesRead = fileInputStream.read(buffer, 0, bufferSize);

                    while (bytesRead > 0)
                    {
                            dos.write(buffer, 0, bufferSize);
                            bytesAvailable = fileInputStream.available();
                            bufferSize = Math.min(bytesAvailable,maxBufferSize);
                            bytesRead = fileInputStream.read(buffer, 0,bufferSize);
                    }
                    dos.writeBytes(lineEnd);
                    dos.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd);

                    // close streams
                    fileInputStream.close();

                    dos.flush();

                    Log.e(Tag,"File Sent, Response: "+String.valueOf(conn.getResponseCode()));

                    InputStream is = conn.getInputStream();

                    // retrieve the response from server
                    int ch;

                    StringBuffer b =new StringBuffer();
                    while( ( ch = is.read() ) != -1 ){ b.append( (char)ch ); }
                    String s=b.toString();
                    Log.i("Response",s);
                    dos.close();
            }
            catch (MalformedURLException ex)
            {
                    Log.e(Tag, "URL error: " + ex.getMessage(), ex);
            }

            catch (IOException ioe)
            {
                    Log.e(Tag, "IO error: " + ioe.getMessage(), ioe);
            }
    }

    @Override
    public void run() {
            // TODO Auto-generated method stub
    }

}

我的 ios 7 代码:

- (void)postUserImage:(NSString *)url postData:(NSMutableDictionary *)imageDetails token:(NSString *)token onSuccess:(HttpRequestSuccess)completion onFailure:(HttpRequestFailure)failure {

    self.httpURL = url;
    self.httpSuccess = completion;
    self.httpFailure = failure;

    NSString *filePath = [imageDetails valueForKey:@"filePath"];
    NSString *fileName = [imageDetails valueForKey:@"fileName"];
    NSData *imageData;
    if ([[NSFileManager defaultManager]fileExistsAtPath:filePath]) {
        NSLog(@"file path exists");
        imageData=[NSData dataWithContentsOfFile:filePath];
    }


    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:url]];
    [request setHTTPMethod:@"POST"];

    [request setCachePolicy:NSURLRequestReloadIgnoringLocalCacheData];
    [request setHTTPShouldHandleCookies:NO];
    [request setTimeoutInterval:30];
    if(token != nil) {
        [request setValue:token forHTTPHeaderField:@"x-owb-token"];
    }

    [request setValue:IOS_CLIENT_ID forHTTPHeaderField:CLIENT_ID];
    [request setValue:IOS_CLIENT_SECRET forHTTPHeaderField:CLIENT_SECRET];
    //[request setValue:@"gzip" forHTTPHeaderField:@"Accept-Encoding"];

    NSString *boundary = @"**********";

    NSString *contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@",boundary];
    [request setValue:contentType forHTTPHeaderField: @"Content-Type"];
    NSMutableData *body = [[NSMutableData alloc]init];

    // giving x,y,w,h

    [body appendData:[[NSString stringWithFormat:@"--%@--\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"x\"\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
    NSString *x=@"0";
    [body appendData:[x dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:[[NSString stringWithFormat:@"--%@--\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];

    [body appendData:[[NSString stringWithFormat:@"--%@--\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"y\"\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
    NSString *y=@"0";
    [body appendData:[y dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:[[NSString stringWithFormat:@"--%@--\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];

    [body appendData:[[NSString stringWithFormat:@"--%@--\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"w\"\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
    NSString *w=@"500";
    [body appendData:[w dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:[[NSString stringWithFormat:@"--%@--\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];

    [body appendData:[[NSString stringWithFormat:@"--%@--\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"h\"\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
    NSString *h=@"500";
    [body appendData:[h dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:[[NSString stringWithFormat:@"--%@--\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];

    // adding Image content

    if (imageData) {

        //[body appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];

        [body appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"file\"; filename=\"%@\"\r\n", fileName] 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]];
        [body appendData:[[NSString stringWithFormat:@"--%@--\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
    }

    [request setHTTPBody:body];


    //NSLog(@"http request body:%@",body);

    //[request setAllHTTPHeaderFields:[request allHTTPHeaderFields]];

    //NSString *postLength = [NSString stringWithFormat:@"%d", [body length]];
    //[request setValue:postLength forHTTPHeaderField:@"Content-Length"];

    NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
    if(connection == nil){
        NSLog(@"BAD CONNECTION");
    }
}

【问题讨论】:

标签: objective-c post ios7 nsurlconnection multipartform-data


【解决方案1】:

几个观察:

  1. 一个问题是请求中存在--(boundary)-- 字符串。它应该只出现在请求的末尾。

  2. 第二个问题是您似乎在每个部分的开始 结束处编写此边界字符串。它应该在每个部分的开头出现一次。即,它应该在两个字段之间只出现一次。

    底线,--(boundary) 应该出现在请求的每个“部分”的开头,--(boundary)-- 字符串应该出现在末尾​​p>

  3. 您已将上传文件的Content-Type 注释掉。我不确定您为什么这样做(如果不是 JPG,则将该内容类型替换为适当的内容类型),但在此过程中,您删除了应该出现在部件标题之后和之前的 \r\n\r\n数据。您现在不仅缺少Content-Type,还缺少\r\n

我建议您使用 Charles 之类的工具观察此请求,并将其与格式正确的请求(例如来自您的 Android 代码)进行比较并进行比较。您应该验证这两个请求看起来是否相同。空行、边界出现和-- 字符串非常重要。

坦率地说,您可能会考虑放弃创建您自己的多部分请求的代码并使用已建立的库,例如 AFNetworking,它可以正确执行此操作。无需重新发明轮子。

【讨论】:

  • 感谢您的提示。我尝试过这个。但现在它显示“内部服务器错误”。
  • 您的请求可能仍然格式不正确。我注意到您在一个部分的末尾和下一个部分的开头都写了边界字符串(因此在两个字段之间出现了两次)。这个边界字符串应该在每个部分的开头出现一次,就是这样。此外,在您上传文件的位置,您不仅注释掉了Content-Type,还注释掉了必要的\r\n
  • 感谢工作。很难找到。同样在我的回复中,我得到一个空白图像。有什么想法吗?
  • @AugustinJose 不,这归结为您的 Web 服务 API 应该返回的内容、请求的精确格式等。您没有向我们展示 Android 代码如何解析响应(更不用说响应应该是一个图像......或者你说它在服务器端是空白的?)。再次,我建议观察与查尔斯之类的成功交易,然后将其与该交易进行比较,并确定确切的不同之处。但没有更多细节,很难说。
  • 感谢您的帮助。我在图像内容上发现了问题。这是因为我传递的 w 和 h(宽度和高度)值非常少。我想在常见的 iPhone 裁剪后传递确切的图像宽度和高度。有什么想法吗?我正在使用图像选择器从相机和图库中获取图像并保存到文档\目录并转换为 NSData。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-11-26
  • 2020-03-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-10-08
相关资源
最近更新 更多