Использование метода добавления FormData для объекта blob в неподдерживаемом браузере

1

При создании запроса Ajax для загруженного пользователем изображения я использую FormData() следующим образом:

var form_data = new FormData();
form_data.append(img_field, img_to_send, img_name);

Обратите внимание, что img_to_send является объектом типа Blob.

Моя проблема заключается в этом небольшом предупреждении о совместимости браузера в веб-документах FormData MDN:

XHR в Android 4.0 отправляет пустой контент для FormData с blob.

Это относится к браузеру Android (версия 4.0). Это означает, что xhr, который я пытаюсь с помощью FormData через append, вероятно, будет терпеть неудачу в этом конкретном браузере.

Мой вопрос: какую альтернативу я могу использовать для обеспечения того, чтобы упомянутый браузер мог правильно обработать xhr (мое требование)? Будет здорово получить иллюстративный пример.

И если альтернатив здесь нет, как мне написать свой код, чтобы он выполнялся только для браузеров, поддерживающих append с помощью объекта blob? Что-то вроде этого?

if (window.FormData.append) {
// xhr code comes here
} 

Я совершенно не уверен в этом.

ps, пожалуйста, придерживайтесь чистой JS для ответа на вопрос.

  • 0
    Я рекомендую вам использовать FileReader и отправлять данные на сервер в двоичном или base64
  • 0
    я предполагаю, что вам нужно загрузить файл с помощью объекта File? пользователь сначала выбирает файл и отправляет его ... справа?
Показать ещё 5 комментариев
Теги:

2 ответа

1
Лучший ответ

... Нелегкая задача...

Первый вопрос, который я задал себе, - это если мне действительно нужно поддерживать этот 7-летний браузер с 0% использования?

Обнаружение функции:

Мы можем с недавних пор проверить, что содержит FormData, с помощью методов get(), has(), entries(), values() и т.д. Но первые спецификации и реализации не имели этих методов и, следовательно, не предлагали никаких средств для обнаружения этого конкретного потока.

У меня нет такого браузера Android 4 для проверки, но я думаю, что у них не было ни одного из этих методов...

Другой современный и немного хакерский способ проверить - использовать ServiceWorker, который должен был бы перехватить фиктивный запрос, чтобы вы знали, был ли ваш Blob хорошо добавлен, но еще раз ServiceWorkers не существовало 7 лет назад.

Это оставляет нам уродливую идентификацию браузера, а не функцию обнаружения (например, синтаксический анализ navigator.userAgent). Я не могу советоваться с этим, потому что он настолько подвержен ошибкам, что может быть лучше просто дать вашему пользователю понять, что это не сработало в ответе вашего сервера.

Временное решение

Возможность отправлять сгенерированный Blob как двоичный файл с помощью другого средства, отличного от FormData, появилась только несколько месяцев назад, и в настоящее время только браузеры Blink поддерживают его изначально, а FF - с помощью эксплойта.

Это означает, что единственным обходным решением для ваших пользователей в Android Browser 4.xxx и для всех браузеров, которые не поддерживают этот метод, было бы сохранить сгенерированный Blob на своем устройстве, а затем выбрать его из <input> и отправьте его через обычный HTML <form>, но это предполагает, что они смогут даже сохранить этот Blob на своем устройстве, и я не могу точно сказать...

Или вы могли бы отправить 30% -ное представление base64 этих данных.

Или, наверное, лучше всего сообщить им, что они должны обновить свой браузер, потому что действительно опасно иметь такой старый браузер, который сейчас стоит в Интернете.


Итак, небольшой пример менее плохих возможностей:

  1. Проверьте, доступна ли форма FormData. В противном случае откат к уродливому b64 в <form>
  2. Отправьте первый раз с оптимальным Blob как многочастным.
  3. На сервере: проверьте, является ли принятый Blob пустым. В этом случае, пусть на стороне будет знать пользовательский ответ.
  4. Если сервер сказал, что не удалось, отправьте еще раз, на этот раз как b64. Поскольку первый раз был пуст, он не должен был быть слишком тяжелым запросом.
  • 0
    Ну, а количество пользователей, с которыми я имею дело (менее 1%), на самом деле используют 4.0.4 и 4.0.3 . Поэтому я подумал, что стоит задать вопрос, если есть удобное решение для этого. Кажется, нет. Я полагаю, что лучшим способом было бы отправить base64 (в случае v4 ). Но тогда из твоего ответа кажется, что сложно определить v4 (или меньше) с точностью. Это означает, что реального «хорошего» решения здесь не существует. Но спасибо за ответ, я немного исправлю его.
  • 0
    Было бы замечательно, если бы можно было проверить, правильно ли добавлен объект BLOB-объекта к объекту FormData, на основании чего можно было бы обработать отступление.
Показать ещё 2 комментария
1

Привет, это небольшой пример того, как отправить файл на сервер как BINARY STRING. С этим вы не нуждаетесь в formData. Вы можете отправить с помощью простой POST. Пожалуйста, измените URL-адрес uploadFile.php на свой URL-адрес. И прочитайте комментарии к примерам переменных, которые ваш сервер должен получить.

     <!DOCTYPE html>

<html>
    <head>
        <title>TODO supply a title</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">


    </head>
    <body>
        <div>
            <input id="btnFile" type="file" accept="image/*" />
        </div>
        <div style="margin-top: 20px; width: 100px; border: solid 1px red">
            <div id="divProgress" style="background-color: red;width: 10px; height: 5px; margin: 1px"></div>
        </div>
        <div style="margin-top: 20px">
            <input id="btnSend" type="button" value="Send File" />
            <input id= "user_id" type="hidden" value="123"/>
        </div>

        <script>



            var btnFile = document.getElementById("btnFile");
            var btnSend = document.getElementById("btnSend");
            var divProgress = document.getElementById("divProgress");



            var selectedFile = null;

            //Register event on file selected or changed.
            addEvents(btnFile, "change", function (event) {
                if (event.target.files.length !== 0) {
                    var file = event.target.files[0];
                    //Check if the file is IMAGE.
                    if (file.type.match("image.*")) {
                        selectedFile = file;
                    } else {
                        selectedFile = null;
                        alert("Please select a IMAGE FILE");
                    }
                } else {
                    selectedFile = null;
                }

            });

            //EVENT BTN SEND.
            addEvents(btnSend, "click", function () {
                if (selectedFile === null) {
                    //Please select a file to upload.
                    alert("Please select the file.");
                    return;
                }

                //File reader object.
                var fl = new FileReader();

                //Add event to read the content file.
                addEvents(fl, "load", function (evt) {
                    //alert(evt.target.result);
                    try {


                        //CONVERT ARRAY BUFFER TO BASE64 STRING.
                        var binaryString = evt.target.result;

                        //NOW YOU CAN SEND SIMPLE POST DATA.
                        var xhr = new XMLHttpRequest();

                        if (supportProgress(xhr)) {
                            addEvents(xhr, "progress", onXHRProgress);
                            addEvents(xhr, "loadstart", onXHRLoadStart);
                            addEvents(xhr, "abort", onXHRAbort);
                        }


                        xhr.open("POST", "/uploadFile.php", true);
                        //xhr.setRequestHeader("Content-Type", "application/json");

                        var user_id = document.getElementById('user_id').value;

                        var myData = {
                            uid: user_id,
                            fileName: selectedFile.name,
                            mimeType: selectedFile.type,
                            extension: getFileExtension(selectedFile),
                            contentFile: binaryString

                        };
                        xhr.send(JSON.stringify(myData));

                        /*
                         * IN YOUR SERVER SIDE YOU GET THE POST VARIABLE.
                         * fileName = The name of the file.
                         * mimeType = example "image/png"
                         * extension = png
                         * conentFile = Binary String of the content file and you can convert the Binary String to File in your disk according extension or mimeType
                         */

                    } catch (e) {

                    }

                });

                //Read the file as arraybuffer.
                fl.readAsBinaryString(selectedFile);
            });


            function onXHRProgress(e) {
                var loaded = 0;
                if (e.lengthComputable) {
                    if (e.loaded === e.total) {
                        loaded = 100;
                        selectedFile = null;
                    } else {
                        loaded = Math.round((e.loaded * 100) / e.total);
                    }

                    //Change the progress here.
                    divProgress.style.width = loaded + "px";
                }
            }

            function onXHRLoadStart() {
                divProgress.style.width = "0px";
            }

            function onXHRAbort() {
                selectedFile = null;

            }



            function getFileExtension(file) {
                var fileName = file.name;
                var i = fileName.toString().lastIndexOf(".");
                if (i !== -1) {
                    return fileName.toString().substring((i + 1), fileName.toString().length).toLowerCase();
                } else {
                    return "";
                }

            }


            function supportProgress(xhr) {
                return !!(xhr && ('upload' in xhr) && ('onprogress' in xhr.upload));
            }

            function addEvents(obj, evtName, func) {
                if (obj.addEventListener !== undefined && obj.addEventListener !== null) {
                    obj.addEventListener(evtName, func, false);
                } else if (obj.attachEvent !== undefined && obj.attachEvent !== null) {
                    obj.attachEvent(evtName, func);
                } else {
                    if (this.getAttribute("on" + evtName) !== undefined) {
                        obj["on" + evtName] = func;
                    } else {
                        obj[evtName] = func;
                    }
                }

            }

            function removeEvents(obj, evtName, func) {
                if (obj.removeEventListener !== undefined && obj.removeEventListener !== null) {
                    obj.removeEventListener(evtName, func, false);
                } else if (obj.detachEvent !== undefined && obj.detachEvent !== null) {
                    obj.detachEvent(evtName, func);
                } else {
                    if (this.getAttribute("on" + evtName) !== undefined) {
                        obj["on" + evtName] = null;
                    } else {
                        obj[evtName] = null;
                    }
                }

            }






        </script>
    </body>
</html>
  • 0
    Это круто, но вот вопрос. Мне также нужно отправить другие параметры вместе с загруженным пользователем изображением. Например, caption к изображению и id пользователя. В настоящее время я просто использую form_data.append("uid", document.getElementById('user_id').value); для user_id (и аналогично для подписи). Как это будет возможно с помощью этого решения?
  • 0
    в строке: xhr.send (JSON.stringify ({имя_файла: selectedFile.name, mimeType: selectedFile.type, расширение: getFileExtension (selectedFile), contentFile: base64String})); Вы можете добавить больше переменной к объекту JSON.
Показать ещё 7 комментариев

Ещё вопросы

Сообщество Overcoder
Наверх
Меню