1

我將一個PDF文件從iOS應用程序上傳到Rails應用程序。 文件已上傳,但其內容類型已損壞。從iOS上傳到Rails的PDF遭到損壞

這裏是(使用AFNetworking庫)iOS的代碼上傳文件的相關部分:

NSURL *url = [NSURL URLWithString:kWebserviceHost]; 
AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:url]; 
// httpClient.parameterEncoding = AFFormURLParameterEncoding; // Experimented with different values, no effect 

NSData *documentData = [NSData dataWithContentsOfURL:self.documentURL]; 
if (! documentData) { 
    NSLog(@"Trying to upload nil document: sorry! - %@", self.documentData); 
    return; 
} 

NSMutableURLRequest *request = [httpClient multipartFormRequestWithMethod:@"PUT" // @"POST" 
                    path:@"new_upload" 
                   parameters:@{ @"fooKey" : fooString, @"barKey" : barString } 
               constructingBodyWithBlock: ^(id <AFMultipartFormData>formData) { 
    [formData appendPartWithFileData:documentData name:@"document" fileName:@"upload.pfd" mimeType:@"application/pdf"]; 
}]; 


AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request]; 
[operation setUploadProgressBlock:^(NSInteger bytesWritten, long long totalBytesWritten, long long totalBytesExpectedToWrite) { 
    NSLog(@"Sent %lld of %lld bytes", totalBytesWritten, totalBytesExpectedToWrite); 
    progressBlock(totalBytesWritten/totalBytesExpectedToWrite); 
}]; 

[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) { 
    uploadSuccessBlock(); 
} failure:^(AFHTTPRequestOperation *operation, NSError *error) { 
    NSLog(@"Sorry, could not upload document - %@", error); 
    failureBlock(error); 
}]; 
[operation start]; 

讓我們去到另一邊,一個Rails 3.2.3服務器。
我正在使用gem PaperClip(版本3.1.4)。這是在我的模型類回形針附件的定義:

paperclip_storage = (Rails.env.production?) ? { 
         :storage  => :s3, 
         :s3_credentials => "#{Rails.root}/config/s3.yml", 
         :path   => ':attachment/:id/:style.:extension', 
         :bucket   => 'mybucketname' #, 
         # :s3_headers => { "Content-Type" => "video/mp4" } 
         } 
        : { :headers => { "Content-Type" => "application/pdf" } 
        } 

has_attached_file :document, paperclip_storage.merge(:use_timestamp => false, 
    :url => "/assets/:id/:basename.:extension", 
    :path => ":rails_root/public/assets/:id/:basename.:extension", 
    :processors => nil # Maybe the processing of the file mess things up? 
) 

我也試圖跳過後處理(即使文件說,因爲沒有風格定義都不應適用)。

before_post_process :skip_post_process 

def skip_post_process 
    return false 
end 

的其他嘗試:在post_process濾波器設置CONTENT_TYPE:

after_post_process :force_content_type_to_pdf 
def force_content_type_to_pdf 
    puts "--------------- Changing content_type" 
    self.document.instance_write(:content_type, "application/pdf") 
end 

這裏是控制器方法來接收和保存文件:

def new_upload 

    @document = Document.create() 
    document = params[:document] 

    if (document.nil?) 
    return 
    end 

    @document.document = document 

    puts "Document type: #{@document.document.content_type}" # logs: 'application/pdf' 
    puts "Parameters: #{params}" # logs  Parameters: {"fooKey"=>"foo", "barKey"=>"bar", "document"=>#<ActionDispatch::Http::UploadedFile:0x007ff5a429be58 @original_filename="upload.pfd", @content_type="application/pdf", @headers="Content-Disposition: form-data; name=\"document\"; filename=\"upload.pfd\"\r\nContent-Type: application/pdf\r\n", @tempfile=#<File:/var/folders/vy/zm_x1bts5hs6pkvzk7clnmvm0000gn/T/RackMultipart20120802-12714-1j0hq6q>>} 


    @document.foo = params['fooKey'] 
    @document.bar = params['barKey'] 

    if @document.save 
    render :json => {status: "saved" } 
    return 
    else 
     render json: @document.errors, status: :unprocessable_entity 
     return 
    end 
end 

文件被上載,但不可讀。 Finder不知道使用哪個應用程序來打開它。
這裏是QuickLook的預覽截圖: QuickLooking the file

內容類型以某種方式混合起來。
file --mime /file/path/before/or/after/upload.pdf在原始文件(將由iOS應用程序上傳的文件)或成功上傳後由Rails服務器創建的文件上返回以下消息:
/upload.pfd: application/pdf; charset=binary。聽起來不錯。

mdls -name kMDItemContentType /file/path/before/upload.pdf對要上傳的文件返回kMDItemContentType = "com.adobe.pdf"。還好。 但是由Rails服務器創建的文件上的相同命令返回:kMDItemContentType = "dyn.ah62d4rv4ge81a3xe"
這至少解釋了Finder爲什麼會感到困惑。

在瀏覽器中下載文件時,問題與此類似。以下是我的控制器的相關方法:

def download_document 
    @document = Document.find(params[:id]) 

    if (@document && @document.document) 
    # Line below propagate the file content-type problem: 
    send_file Rails.root.join(document.path), :type => "application/pdf", :x_sendfile => false, :stream => false 

    # This hack works while server is locally hosted 
    send_data File.read(Rails.root.join(@document.document.path)), :type => "application/pdf" 
    end 
end 

不幸的是,在S3上託管時,hack將不會正常工作。而且它妨礙我在調試iOS應用程序時瀏覽我的文件系統以查看上傳的文檔。
直接從S3下載文件通過一個FTP客戶端,如發送給我同樣的損壞的文件。

什麼問題?您認爲我應該在哪些方面進一步排除故障,客戶端或服務器?怎麼樣?任何想法,提示,預測或斷言的東西?

如果您沒有任何解決方案,我也很樂意爲您提供一個臨時修復程序,在下載它之後,再次正確設置損壞文件中的content_type(或任何問題所在)。

回答

3

如果您將上傳的文件命名爲「upload.pdf」而不是「upload.pfd」,會發生什麼情況?

+0

NOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO!有用。爲什麼Preview.app在使用「Open With ...」命令時無法打開它?刪除擴展程序允許強制使用預覽打開它,但沒有任何反應(沒有窗口打開,控制檯中沒有日誌)。 – Guillaume 2012-08-03 07:40:41