3
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Javascript Remoting で input too long エラーを回避する

Last updated at Posted at 2017-06-24

#Javascript Remoting の引数の上限文字数は 1,000,000 文字
Visualforce ページから任意のレコードに対し添付ファイルをアップロードしようとすると、「input too long」エラーで怒られてしまう事がよくあります。
Visualforce から非同期で Apex と通信できる Javascript Remoting では、その引数の長さが 1,000,000 文字を超えることが出来ません。
そのため、base64 エンコードしたファイルなどを渡す際は少し工夫する必要があります。

#Apex の String 型変数の上限文字数は 6,000,000 文字
以下にその対処方法の例を記載していますが、これも万能ではありません。
base64 でエンコーディングした文字列は Apex 上で String として扱われます。Apex の String 型変数の上限文字数は 6,000,000 文字となるため、約 5MB 弱のサイズのファイルしか扱えないことに注意してください。

#input too long エラーを回避するサンプルコード
基本的な対応方針は、multipart リクエストのように、送信するデータを分割し末尾再帰的に複数回に分けて送信します。
それに合わせて、Apex コードではデータ文字列を結合する事で復元しながら保存していきます。

AttachmentUpload.vfp
<apex:page controller="AttachmentUploadController" >
    <input id="js-input-file" type="file" />   
    <input type="button" value="送信" onclick="submit()" />
    
    <script>
    function submit() {
        // ファイルを取得
        var file = document.getElementById('js-input-file').files[0];
        
        // file を読み込む
        var reader = new FileReader();
        reader.readAsDataURL(file);
        reader.onload = function () {
            // 親レコードの ID、ファイル名、ファイルの data uri を指定する。
            uploadAttachment('0016F00001puC19', file.name, reader.result);
        };
        reader.onerror = function (error) {
            console.log('ERROR: ', error);
        };
    }
    
    
    
    var maxSizeForApexString = 6000000; // Apex の String 型変数の最大文字数
    var chunkSize            =  950000; // Javascript Remoting で一度に送信したい文字数の上限
   
    function uploadAttachment(parentId, fileName, dataURI) {
        var contentType = dataURI.split(',')[0].split(':')[1].split(';')[0]; 
        var dataString  = dataURI.split(',')[1];
        var recordId    = null;
        var curIndex    = 0;
        if(dataString.length < maxSizeForApexString) {
            console.log('Start uploading');
            upload(parentId, recordId, fileName, contentType, dataString, curIndex);
        } else {
            alert("File is too big.");
        }
    }
    
    function upload(parentId, recordId, fileName, contentType, dataString, curIndex) {
        var chunk = dataString.slice(curIndex, curIndex + chunkSize);
        curIndex += chunkSize;
        AttachmentUploadController.uploadAttachment(
            parentId, recordId, fileName, contentType, chunk,
            function(result, event) {
                if (event.status) {
                    if (curIndex > dataString.length) {
                        console.log('Uploading completed');
                    } else {
                        console.log('data sent: ' + curIndex + '/' +  dataString.length);
                        upload(parentId, result, fileName, contentType, dataString, curIndex);
                    } 
                } else if (event.type === 'exception') {
                    console.error("EXCEPTION: " + event.message);
                } else {
                    console.error("ERROR: " + event.message);
                }                
            },
            { buffer: false, escape: true, timeout: 30000 }
        );
    }
    </script>
</apex:page>
AttachmentUploadController.apxc
public class AttachmentUploadController {
    @RemoteAction
    public static String uploadAttachment(String parentId, String recordId, String fileName, String contentType, String dataString) {
        Attachment attachment;
        if (String.isEmpty(recordId)) {
            attachment = new Attachment(Name=fileName, ContentType=contentType, parentId=parentId, Body=EncodingUtil.base64Decode(dataString));
        } else {
            attachment = [SELECT Id, Body FROM Attachment WHERE Id =: recordId];
            String currentBody = EncodingUtil.base64Encode(attachment.Body);
            attachment.Body = EncodingUtil.base64Decode(currentBody + dataString);
        }
        upsert attachment;
        return attachment.Id;
    }
}

#添付ファイル以外のファイル送信

Files

FileUploadController.apxc
public class FileUploadController {
    @RemoteAction
    public static String uploadFileAndLinkTo(String parentId, String recordId, String fileName, String dataString) {
        ContentVersion content;
        if (String.isEmpty(recordId)) {
            content = new ContentVersion(Title=fileName, VersionData=EncodingUtil.base64Decode(dataString), PathOnClient='/' + fileName);
            insert content;
            content = [select id, ContentDocumentId from ContentVersion WHERE Id =: content.Id];
            ContentDocumentLink link = new ContentDocumentLink(ContentDocumentId=content.ContentDocumentId, LinkedEntityId=parentId, ShareType='V', Visibility='AllUsers');
            insert link;
        } else {
            ContentVersion partialContent = [SELECT Id, ContentDocumentId, VersionData FROM ContentVersion WHERE Id =: recordId];
            String currentData = EncodingUtil.base64Encode(partialContent.VersionData);
            content = new ContentVersion(Title=fileName, PathOnClient='/' + fileName, ContentDocumentId=partialContent.ContentDocumentId);
            content.VersionData = EncodingUtil.base64Decode(currentData + dataString);
            insert content;
        }
        return content.Id;
    }
}
3
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?