JavaScript / jQuery для загрузки файла через POST с данными JSON - PullRequest
233 голосов
/ 17 августа 2010

У меня есть одностраничное веб-приложение на основе jquery. Он связывается с веб-сервисом RESTful через вызовы AJAX.

Я пытаюсь сделать следующее:

  1. Отправка сообщения POST, содержащего данные JSON, в URL-адрес REST.
  2. Если в запросе указан ответ JSON, возвращается JSON.
  3. Если в запросе указан ответ PDF / XLS / etc, возвращается загружаемый двоичный файл.

У меня сейчас работают 1 и 2, и клиентское приложение jquery отображает возвращенные данные на веб-странице, создавая элементы DOM на основе данных JSON. У меня также есть # 3, работающий с точки зрения веб-сервиса, то есть он создаст и вернет двоичный файл, если ему будут заданы правильные параметры JSON. Но я не уверен, что лучший способ справиться с №3 в клиентском JavaScript-коде.

Можно ли получить загружаемый файл обратно с помощью вызова ajax, подобного этому? Как получить браузер для загрузки и сохранения файла?

$.ajax({
    type: "POST",
    url: "/services/test",
    contentType: "application/json",
    data: JSON.stringify({category: 42, sort: 3, type: "pdf"}),
    dataType: "json",
    success: function(json, status){
        if (status != "success") {
            log("Error loading data");
            return;
        }
        log("Data loaded!");
    },
    error: function(result, status, err) {
        log("Error loading data");
        return;
    }
});

Сервер отвечает следующими заголовками:

Content-Disposition:attachment; filename=export-1282022272283.pdf
Content-Length:5120
Content-Type:application/pdf
Server:Jetty(6.1.11)

Другая идея состоит в том, чтобы сгенерировать PDF-файл и сохранить его на сервере и вернуть JSON, содержащий URL-адрес файла. Затем выполните другой вызов в обработчике успеха ajax, чтобы сделать что-то вроде следующего:

success: function(json,status) {
    window.location.href = json.url;
}

Но это означает, что мне нужно будет сделать более одного вызова на сервер, и мой сервер должен будет создавать загружаемые файлы, хранить их где-то, а затем периодически очищать эту область хранения.

Должен быть более простой способ сделать это. Идеи?


РЕДАКТИРОВАТЬ: После просмотра документов для $ .ajax, я вижу, что dataType ответа может быть только один из xml, html, script, json, jsonp, text, поэтому я предполагаю, что нет способа напрямую загрузить файл с помощью запроса AJAX, если я не внедрить двоичный файл с использованием схемы Data URI, как предложено в ответе @VinayC (что я не хочу делать).

Итак, я думаю, мои варианты:

  1. Не используйте ajax, вместо этого отправьте сообщение формы и вставьте мои данные JSON в значения формы. Вероятно, придется возиться со скрытыми iframes и тому подобное.

  2. Не использовать ajax, а вместо этого преобразовать мои данные JSON в строку запроса для создания стандартного запроса GET и установить для window.location.href этот URL. Может потребоваться использовать event.preventDefault () в моем обработчике кликов, чтобы браузер не менял URL приложения.

  3. Используйте мою другую идею выше, но дополненную предложениями из ответа @naikus. Отправьте AJAX-запрос с некоторым параметром, который позволяет веб-сервису узнать, что он вызывается через AJAX-вызов. Если веб-служба вызывается из вызова ajax, просто верните JSON с URL-адресом сгенерированного ресурса. Если ресурс вызывается напрямую, верните фактический двоичный файл.

Чем больше я об этом думаю, тем больше мне нравится последний вариант. Таким образом, я могу получить информацию о запросе (время генерации, размер файла, сообщения об ошибках и т. Д.), И я могу обработать эту информацию перед началом загрузки. Недостатком является дополнительное управление файлами на сервере.

Есть ли другие способы сделать это? Какие-нибудь плюсы / минусы этих методов мне следует знать?

Ответы [ 12 ]

1 голос
/ 01 сентября 2015

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

Клиентская сторона

function exportStaffCSV(t) {
   
    var postData = { checkOne: t };
    $.ajax({
        type: "POST",
        url: "/Admin/Staff/exportStaffAsCSV",
        data: postData,
        success: function (data) {
            SuccessMessage("file download will start in few second..");
            var url = '/Admin/Staff/DownloadCSV?data=' + data;
            window.location = url;
        },
       
        traditional: true,
        error: function (xhr, status, p3, p4) {
            var err = "Error " + " " + status + " " + p3 + " " + p4;
            if (xhr.responseText && xhr.responseText[0] == "{")
                err = JSON.parse(xhr.responseText).Message;
            ErrorMessage(err);
        }
    });

}

Серверная сторона

 [HttpPost]
    public string exportStaffAsCSV(IEnumerable<string> checkOne)
    {
        StringWriter sw = new StringWriter();
        try
        {
            var data = _db.staffInfoes.Where(t => checkOne.Contains(t.staffID)).ToList();
            sw.WriteLine("\"First Name\",\"Last Name\",\"Other Name\",\"Phone Number\",\"Email Address\",\"Contact Address\",\"Date of Joining\"");
            foreach (var item in data)
            {
                sw.WriteLine(string.Format("\"{0}\",\"{1}\",\"{2}\",\"{3}\",\"{4}\",\"{5}\",\"{6}\"",
                    item.firstName,
                    item.lastName,
                    item.otherName,
                    item.phone,
                    item.email,
                    item.contact_Address,
                    item.doj
                    ));
            }
        }
        catch (Exception e)
        {

        }
        return sw.ToString();

    }

    //On ajax success request, it will be redirected to this method as a Get verb request with the returned date(string)
    public FileContentResult DownloadCSV(string data)
    {
        return File(new System.Text.UTF8Encoding().GetBytes(data), System.Net.Mime.MediaTypeNames.Application.Octet, filename);
        //this method will now return the file for download or open.
    }

Удачи.

0 голосов
/ 19 мая 2015

Другой подход, вместо того, чтобы сохранять файл на сервере и извлекать его, заключается в использовании .NET 4.0+ ObjectCache с коротким сроком действия до второго действия (когда он может быть окончательно выгружен).Причина, по которой я хочу использовать JQuery Ajax для вызова, заключается в том, что он асинхронный.Создание моего динамического файла PDF занимает довольно много времени, и в течение этого времени я отображаю диалоговое окно с вращающимся вертелом (оно также позволяет выполнять другую работу).Подход с использованием данных, возвращаемых в «success:», для создания BLOB-объектов не работает надежно.Это зависит от содержимого файла PDF.Он легко искажается данными в ответе, если он не полностью текстовый, и это все, что может обработать Ajax.

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