Objective C - NodeJS - 如何将特定文件(不是图像)从 iOS 应用程序上传到服务器?

Posted

技术标签:

【中文标题】Objective C - NodeJS - 如何将特定文件(不是图像)从 iOS 应用程序上传到服务器?【英文标题】:Objective C - NodeJS - How to upload a specific file (not an image) from the iOS app to the server? 【发布时间】:2016-10-13 09:00:27 【问题描述】:

我需要使用nodeJS 将包含一些标题信息和许多点(x、y、z)的文件上传到服务器(现在是本地主机)。

现在我可以使用 iOS 端的代码正确上传 png 文件:

- (IBAction)uploadFileButton:(id)sender 
    NSLog(@"Going to upload file");
    NSMutableURLRequest* request = [[NSMutableURLRequest alloc] init];
    [request setURL:[NSURL URLWithString:"http://localhost:3000/"]];

    request.HTTPMethod = @"POST";
    [request addValue:@"image/png" forHTTPHeaderField:@"Content-Type"];

    NSURLSessionConfiguration* config = [NSURLSessionConfiguration defaultSessionConfiguration];
    NSURLSession* session = [NSURLSession sessionWithConfiguration:config];
    //UIImagePNGRepresentation turns an instance of UIImage into PNG file data.
    NSData* bytes = UIImagePNGRepresentation(self.imageView.image);//a random image displayed on my ios view for testing purpose

    NSURLSessionUploadTask* task = [session uploadTaskWithRequest:request fromData:bytes completionHandler:^(NSData *data, NSURLResponse *response, NSError *error)  //5
        if (error == nil && [(NSHTTPURLResponse*)response statusCode] < 300) 
            NSDictionary* responseDict = [NSJSONSerialization JSONObjectWithData:data options:0 error:NULL];

        
    ];
    [task resume];

服务器端使用这段代码(只是有趣的部分):

app.post('/',function(req,res)
   //This looks up the value of the Content-Type header which is set by the mobile app.
    var ctype = req.get("content-type");
    //This tries to guess the file extension based upon the content type. For instance, an image/png should have a png extension.
    var ext = ctype.substr(ctype.indexOf('/')+1); 
    if (ext) ext = '.' + ext;  else ext = '';

    //Create a filename by appending the appropriate extension to the new id.    
    var filename = "test" + ext;
    console.log("filename : " + filename);
    //The designated path to the file is in the server’s root directory, under the uploads sub-folder. __dirname is the Node.js value of the executing script’s directory.
    filePath = __dirname + '/uploads/' + filename; 

     console.log("filepath : " + filePath);
    var writable = fs.createWriteStream(filePath); 

    req.pipe(writable); 
    req.on('end', function () 
      res.send(201, "ok");
    );        

    writable.on('error', function(err)  
      res.send(500,err);
      console.log("Error uploading file.");
    );

);

到目前为止,经过一番努力,我能够将 png 文件上传到上传目录。

现在我想进一步上传具有特定扩展名的特定文件。

我试图改变

[request addValue:@"image/png" forHTTPHeaderField:@"Content-Type"];

 [request addValue:@"application/octet-stream" forHTTPHeaderField:@"Content-Type"];

但我对转换为 NSData 类型感到困惑。

那么您知道如何将文件(不是图像)上传到我的服务器吗?我尝试在互联网上搜索,但没有找到任何相关答案。

但是,我想知道,是否可能需要将我的文件转换为 json 文件,然后将其上传到服务器? (我觉得上传json文件比较容易。)

你能帮帮我吗?

非常感谢您的帮助。

编辑:尝试使用 AFNetworking 仍无法正常工作

我尝试使用库AFNetworking 使用以下代码,但它不起作用。我没有任何错误。

   NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
    AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:configuration];

   manager.responseSerializer = [AFHTTPResponseSerializer serializer];

  manager.responseSerializer = [AFHTTPResponseSerializer serializer];

    NSURL *URL = [NSURL URLWithString:"http://localhost:3000/"];
    NSURLRequest *request = [NSURLRequest requestWithURL:URL];

    NSString *documentsDirectoryPath = [NSSearchPathForDirectoriesInDomains( NSDocumentDirectory, NSUserDomainMask, YES ) objectAtIndex:0];
    NSString *data = @"Model.pcd";
    NSString *data_path = [documentsDirectoryPath stringByAppendingPathComponent:data];
    NSLog(@"path: %@ ", data_path);

    NSURL *filePath = [NSURL fileURLWithPath:data_path];
    NSURLSessionUploadTask *uploadTask = [manager uploadTaskWithRequest:request fromFile:filePath progress:nil completionHandler:^(NSURLResponse *response, id responseObject, NSError *error) 
        if (error) 
            NSLog(@"[INFO] Error: %@", error);
         else 
            NSLog(@"[INFO]Upload successfully : %@ %@", response, responseObject);
        
    ];
    [uploadTask resume];

首先我遇到了以下错误:

NSLocalizedDescription=Request failed: unacceptable content-type: text/html

但是通过添加manager.responseSerializer = [AFHTTPResponseSerializer serializer]; 我没有任何错误。

但是上传失败了……

我的输出如下:

NSHTTPURLResponse: 0x6180002310a0>  URL: http://localhost:3000/   status code: 200, headers 
    "Accept-Ranges" = bytes;
    "Cache-Control" = "public, max-age=0";
    Connection = "keep-alive";
    "Content-Length" = 233;
    "Content-Type" = "text/html; charset=UTF-8";
    Date = "Thu, 13 Oct 2016 12:03:58 GMT";
    Etag = "\"233-1476189758000\"";
    "Last-Modified" = "Tue, 11 Oct 2016 12:42:38 GMT";
    "X-Powered-By" = Express;
  <3c666f72 6d206964 20202020 20202020 3d202022 75706c6f 6164466f 726d220a 20202020 20656e63 74797065 2020203d 2020226d 756c7469 70617274 2f666f72 6d2d6461 7461220a 20202020 20616374 696f6e20 2020203d 2020222f 6170692f 70686f74 6f220a20 20202020 6d657468 6f642020 20203d20 2022706f 7374220a 3e0a3c69 6e707574 20747970 653d2266 696c6522 206e616d 653d2275 73657250 686f746f 22202f3e 0a3c696e 70757420 74797065 3d227375 626d6974 22207661 6c75653d 2255706c 6f616420 496d6167 6522206e 616d653d 22737562 6d697422 3e0a3c2f 666f726d 3e>

【问题讨论】:

你必须更改上传代码看看我的ans包含一些工作链接。 不是解决方案,但您可以在块中帮助您调试:if ([responseObject isKindOfClass:[NSData class]])NSLog(@"responseObject: %@", [[NSString alloc] initWithData: responseObject encoding:NSUTF8StringEncoding]; 而不是打印无济于事的 NSData ;) 【参考方案1】:

好吧,我费了很多力气,但最后我能够使用两种方法上传文件:Multer 和 AFNetworking。

实际上,我的表单有错误,所以什么也没发生。 这里是 iOS 方面的代码:

//Content type
NSDictionary *params = @@"enctype": @"multipart/form-data";
NSLog(@"Upload file...");

//Path to the local file (TODO : need to change once the app will be on the ipad)
NSString *path_data = @"file.xyz";
//Check if the file exist
BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:cloud_pcd_path];
if (!fileExists)
    NSLog(@"ERROR - FILE NOT EXIST ");
    return;


//Transform the data to NSData for sending to the server
NSData *cloudData = [NSData dataWithContentsOfFile:path_data];


//Create a HTTP request type POST for sending the data
NSMutableURLRequest *request = [[AFHTTPRequestSerializer serializer] multipartFormRequestWithMethod:@"POST" URLString:kBaseURL
                                                                            parameters:params constructingBodyWithBlock:^(id<AFMultipartFormData>  _Nonnull formData) 
    /// Add attributes to the forms for using then in NodeJS
    [formData appendPartWithFileData:cloudData
                                name:@"data"
                            fileName:@"file.xyz"
                            mimeType:@"text/plain"];

 error:nil];


[request setCachePolicy:NSURLRequestReloadIgnoringLocalCacheData];
[request setHTTPShouldHandleCookies:NO];
[request setTimeoutInterval:20];

AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];


manager.responseSerializer = [AFHTTPResponseSerializer serializer];
//Upload it
//Upload tasks are used for making HTTP requests that require a request body
NSURLSessionUploadTask *uploadTask;

// Create a progress object and pass it in
__block NSProgress *prog;
uploadTask = [manager uploadTaskWithStreamedRequest:request
                                           progress:^(NSProgress *_Nonnull progress)
                                               [progress addObserver:self
                                                          forKeyPath:@"fractionCompleted"
                                                             options:NSKeyValueObservingOptionNew
                                                             context:NULL];

                                               prog = progress;
                                              // [self unregisterAsObserverForObject:progress];
                                           
                                  completionHandler:^(NSURLResponse * response, id responseObject, NSError * error)

    if (error) 
        NSLog(@"[INFO] ERROR: %@", error);
     else 
        NSLog(@"[INFO] Upload completed");
    

];

以及 NodeJS 中使用 Multer 的代码:

//Parameters for uploading file
var storage = multer.diskStorage(
    destination: function (request, file, callback) 
        callback(null, './uploads/');
    ,
    filename: function (request, file, callback) 
        console.log(file);
        callback(null, file.originalname)
    
);

var upload = multer( storage: storage ).single('data');

router.get('/', function (req, res, next) 
    res.send('<html><body><h1>Upload</h1></body></html>');

);


router.post('/', function (req, res) 
  upload(req, res, function (err) 
    if (err) 
      // An error occurred when uploading
      console.log("ERROR during the upload");
      return

    else 
    


        // Everything went fine
    console.log("File uploaded : ",req.file.originalname);
    console.log("Saved to : ",req.file.destination);
  res.status(204).end()

 
  )

);

我现在可以继续我的项目了。

谢谢

【讨论】:

如果它解决了你的问题,你应该接受你的答案。

以上是关于Objective C - NodeJS - 如何将特定文件(不是图像)从 iOS 应用程序上传到服务器?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Objective C 中执行 chmod()

Objective - C,我如何裁剪 .caf 文件?

如何在Objective c中获取目录中文件的创建日期

如何在混合代码 Objective-C/C++ 文件(.mm 文件)中使用 PHPhotoLibrary?

Objective - C 如何使用 View Controller iphone 管理多个视图

如何在 C / Objective-C 中将字符串文字拆分为多行?