JavaScript / jQuery để tải xuống tệp qua POST với dữ liệu JSON


250

Tôi có một ứng dụng web một trang dựa trên jquery. Nó giao tiếp với một dịch vụ web RESTful thông qua các cuộc gọi AJAX.

Tôi đang cố gắng thực hiện như sau:

  1. Gửi một POST có chứa dữ liệu JSON đến một url REST.
  2. Nếu yêu cầu chỉ định một phản hồi JSON, thì JSON được trả về.
  3. Nếu yêu cầu chỉ định phản hồi PDF / XLS / etc, thì tệp nhị phân có thể tải xuống được trả về.

Bây giờ tôi có 1 & 2 hoạt động và ứng dụng jquery của khách hàng hiển thị dữ liệu được trả về trong trang web bằng cách tạo các phần tử DOM dựa trên dữ liệu JSON. Tôi cũng có # 3 làm việc theo quan điểm dịch vụ web, nghĩa là nó sẽ tạo và trả về một tệp nhị phân nếu được cung cấp các tham số JSON chính xác. Nhưng tôi không chắc chắn cách tốt nhất để xử lý số 3 trong mã javascript của máy khách.

Có thể lấy lại một tệp có thể tải xuống từ một cuộc gọi ajax như thế này không? Làm cách nào để tải xuống trình duyệt và lưu tệp?

$.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;
    }
});

Máy chủ trả lời với các tiêu đề sau:

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

Một ý tưởng khác là tạo tệp PDF và lưu trữ nó trên máy chủ và trả về JSON có chứa URL cho tệp. Sau đó, đưa ra một cuộc gọi khác trong trình xử lý thành công ajax để thực hiện một số thao tác như sau:

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

Nhưng làm điều đó có nghĩa là tôi sẽ cần thực hiện nhiều cuộc gọi đến máy chủ và máy chủ của tôi sẽ cần xây dựng các tệp có thể tải xuống, lưu trữ chúng ở đâu đó, sau đó định kỳ dọn sạch vùng lưu trữ đó.

Phải có một cách đơn giản hơn để thực hiện điều này. Ý tưởng?


EDIT: Sau khi xem xét các tài liệu cho $ .ajax, tôi thấy rằng dataType phản hồi chỉ có thể là một trong số đó xml, html, script, json, jsonp, text, vì vậy tôi đoán không có cách nào để tải xuống trực tiếp một tệp bằng yêu cầu ajax, trừ khi tôi nhúng tệp nhị phân vào sử dụng Lược đồ URI dữ liệu như được đề xuất trong câu trả lời @VinayC (đây không phải là điều tôi muốn làm).

Vì vậy, tôi đoán các lựa chọn của tôi là:

  1. Không sử dụng ajax và thay vào đó hãy gửi một bài đăng mẫu và nhúng dữ liệu JSON của tôi vào các giá trị của biểu mẫu. Có lẽ sẽ cần phải lộn xộn với iframe ẩn và như vậy.

  2. Không sử dụng ajax và thay vào đó chuyển đổi dữ liệu JSON của tôi thành chuỗi truy vấn để xây dựng yêu cầu GET tiêu chuẩn và đặt window.location.href thành URL này. Có thể cần sử dụng event.preventDefault () trong trình xử lý nhấp chuột của tôi để ngăn trình duyệt thay đổi từ URL ứng dụng.

  3. Sử dụng ý tưởng khác của tôi ở trên, nhưng được tăng cường với các đề xuất từ ​​câu trả lời @naikus. Gửi yêu cầu AJAX với một số tham số cho phép dịch vụ web biết điều này đang được gọi thông qua một cuộc gọi ajax. Nếu dịch vụ web được gọi từ một cuộc gọi ajax, chỉ cần trả lại JSON có URL cho tài nguyên được tạo. Nếu tài nguyên được gọi trực tiếp, sau đó trả về tệp nhị phân thực tế.

Càng nghĩ về nó, tôi càng thích lựa chọn cuối cùng. Bằng cách này, tôi có thể lấy lại thông tin về yêu cầu (thời gian tạo, kích thước tệp, thông báo lỗi, v.v.) và tôi có thể hành động theo thông tin đó trước khi bắt đầu tải xuống. Nhược điểm là quản lý tập tin thêm trên máy chủ.

Bất kỳ cách nào khác để thực hiện điều này? Bất kỳ ưu / nhược điểm nào đối với các phương pháp này tôi nên biết?



6
cái này là "một chút" trước đó, vì vậy nó là một bản sao
GiM 13/03/2015

1
url = 'http://localhost/file.php?file='+ $('input').val(); window.open(url); Cách dễ dàng để có được kết quả tương tự. Đặt tiêu đề trong tập tin php. Không cần gửi bất kỳ ajax hoặc nhận yêu cầu
abhishek bagul

Câu trả lời:


171

Giải pháp của letronje chỉ hoạt động cho các trang rất đơn giản. document.body.innerHTML +=lấy văn bản HTML của phần thân, nối thêm iframe HTML và đặt bên trongHTML của trang vào chuỗi đó. Điều này sẽ xóa sạch mọi ràng buộc sự kiện mà trang của bạn có, trong số những thứ khác. Tạo một yếu tố và sử dụng appendChildthay thế.

$.post('/create_binary_file.php', postData, function(retData) {
  var iframe = document.createElement("iframe");
  iframe.setAttribute("src", retData.url);
  iframe.setAttribute("style", "display: none");
  document.body.appendChild(iframe);
}); 

Hoặc sử dụng jQuery

$.post('/create_binary_file.php', postData, function(retData) {
  $("body").append("<iframe src='" + retData.url+ "' style='display: none;' ></iframe>");
}); 

Điều này thực sự làm gì: thực hiện một bài đăng tới /create_binary_file.php với dữ liệu trong biến postData; nếu bài đăng đó hoàn thành thành công, hãy thêm iframe mới vào phần thân của trang. Giả định là phản hồi từ /create_binary_file.php sẽ bao gồm một giá trị 'url', đó là URL mà tệp PDF / XLS / etc được tạo có thể được tải xuống từ đó. Thêm iframe vào trang tham chiếu URL đó sẽ dẫn đến trình duyệt thúc đẩy người dùng tải xuống tệp, giả sử rằng máy chủ web có cấu hình loại mime phù hợp.


1
Tôi đồng ý, điều này tốt hơn so với việc sử dụng +=và tôi sẽ cập nhật ứng dụng của mình cho phù hợp. Cảm ơn!
Tauren

3
Tôi thích khái niệm này, tuy nhiên Chrome có thông báo này trong bảng điều khiển : Resource interpreted as Document but transferred with MIME type application/pdf. Sau đó, nó cũng cảnh báo tôi các tập tin có thể nguy hiểm. Nếu tôi truy cập retData.url trực tiếp, không có cảnh báo hoặc vấn đề nào.
Michael Irey

Nhìn trên internet, có vẻ như bạn có thể gặp sự cố với các tệp PDF trong iFrames nếu máy chủ của bạn không đặt Kiểu nội dung và Bố trí nội dung đúng cách. Tôi đã không thực sự sử dụng giải pháp này cho mình, chỉ cần làm rõ một giải pháp trước đó, vì vậy tôi không có lời khuyên nào khác.
SamStephens

1
@Tauren: Nếu bạn đồng ý rằng đây là câu trả lời tốt hơn, hãy lưu ý rằng bạn có thể chuyển câu trả lời được chấp nhận bất cứ lúc nào - hoặc thậm chí xóa hoàn toàn dấu chấp nhận. Chỉ cần kiểm tra câu trả lời mới và dấu chấp nhận sẽ được chuyển. (Câu hỏi cũ, nhưng nó đã được đưa lên cờ gần đây.)
BoltClock

5
retData.url giả sử là gì?
Đánh dấu Thiên

48

Tôi đã chơi xung quanh với một tùy chọn khác sử dụng các đốm màu. Tôi đã quản lý để tải xuống tài liệu văn bản và tôi đã tải xuống bản PDF (Tuy nhiên, chúng bị hỏng).

Sử dụng API blob, bạn sẽ có thể thực hiện các thao tác sau:

$.post(/*...*/,function (result)
{
    var blob=new Blob([result]);
    var link=document.createElement('a');
    link.href=window.URL.createObjectURL(blob);
    link.download="myFileName.txt";
    link.click();

});

Đây là IE 10+, Chrome 8+, FF 4+. Xem https://developer.mozilla.org/en-US/docs/Web/API/URL.createObjectURL

Nó sẽ chỉ tải xuống tệp trong Chrome, Firefox và Opera. Điều này sử dụng một thuộc tính tải xuống trên thẻ neo để buộc trình duyệt tải xuống.


1
Không hỗ trợ cho thuộc tính tải xuống trên IE và Safari :( ( caniuse.com/#feat=doad ). Bạn có thể mở một cửa sổ mới và đặt nội dung ở đó, nhưng không chắc chắn về PDF hoặc Excel ...
Marçal Juan

1
Bạn nên giải phóng bộ nhớ trình duyệt sau khi gọi click:window.URL.revokeObjectURL(link.href);
Edward Brey

@JoshBerke Cái này cũ nhưng nó hoạt động được. Làm thế nào tôi có thể làm cho nó mở thư mục của tôi ngay lập tức để lưu thay vì lưu vào trình duyệt của tôi? Ngoài ra có cách nào để xác định tên của tệp đến?
Jo Ko

2
Nó sẽ làm hỏng các tệp nhị phân, vì chúng được chuyển đổi thành các chuỗi bằng cách sử dụng mã hóa và kết quả không gần với nhị phân ban đầu ...
Gobol

2
Có thể sử dụng mimetypes để không làm hỏng thông tin như được sử dụng ở đây với các tệp PDF: alexhadik.com/blog/2016/7/7/l8ztp8kr5lbctf5qns4l8t3646npqh
Mateo Tibaquira

18

Tôi biết loại cũ này, nhưng tôi nghĩ rằng tôi đã đưa ra một giải pháp thanh lịch hơn. Tôi cũng có chính xác vấn đề đấy. Vấn đề tôi gặp phải với các giải pháp được đề xuất là tất cả chúng đều yêu cầu tệp được lưu trên máy chủ, nhưng tôi không muốn lưu tệp trên máy chủ, vì nó đã giới thiệu các vấn đề khác (bảo mật: tệp có thể được truy cập bởi người dùng không xác thực, dọn dẹp: làm thế nào và khi nào bạn thoát khỏi các tập tin). Và giống như bạn, dữ liệu của tôi là các đối tượng JSON lồng nhau, phức tạp, khó có thể đưa vào một biểu mẫu.

Những gì tôi đã làm là tạo ra hai chức năng máy chủ. Việc đầu tiên xác nhận dữ liệu. Nếu có lỗi, nó sẽ được trả lại. Nếu đó không phải là một lỗi, tôi đã trả về tất cả các tham số được tuần tự hóa / mã hóa dưới dạng chuỗi base64. Sau đó, trên máy khách, tôi có một biểu mẫu chỉ có một đầu vào ẩn và đăng lên chức năng máy chủ thứ hai. Tôi đặt đầu vào ẩn cho chuỗi base64 và gửi định dạng. Hàm máy chủ thứ hai giải mã / giải tuần tự các tham số và tạo tệp. Biểu mẫu có thể gửi đến một cửa sổ mới hoặc iframe trên trang và tệp sẽ mở ra.

Có thêm một chút công việc liên quan, và có lẽ xử lý nhiều hơn một chút, nhưng nhìn chung, tôi cảm thấy tốt hơn nhiều với giải pháp này.

Mã nằm trong C # / MVC

    public JsonResult Validate(int reportId, string format, ReportParamModel[] parameters)
    {
        // TODO: do validation

        if (valid)
        {
            GenerateParams generateParams = new GenerateParams(reportId, format, parameters);

            string data = new EntityBase64Converter<GenerateParams>().ToBase64(generateParams);

            return Json(new { State = "Success", Data = data });
        }

        return Json(new { State = "Error", Data = "Error message" });
    }

    public ActionResult Generate(string data)
    {
        GenerateParams generateParams = new EntityBase64Converter<GenerateParams>().ToEntity(data);

        // TODO: Generate file

        return File(bytes, mimeType);
    }

trên máy khách

    function generate(reportId, format, parameters)
    {
        var data = {
            reportId: reportId,
            format: format,
            params: params
        };

        $.ajax(
        {
            url: "/Validate",
            type: 'POST',
            data: JSON.stringify(data),
            dataType: 'json',
            contentType: 'application/json; charset=utf-8',
            success: generateComplete
        });
    }

    function generateComplete(result)
    {
        if (result.State == "Success")
        {
            // this could/should already be set in the HTML
            formGenerate.action = "/Generate";
            formGenerate.target = iframeFile;

            hidData = result.Data;
            formGenerate.submit();
        }
        else
            // TODO: display error messages
    }

1
Tôi chưa có một cái nhìn tốt về giải pháp này, nhưng đáng chú ý là không có gì về giải pháp sử dụng create_binary_file.php yêu cầu các tệp phải được lưu vào đĩa. Sẽ hoàn toàn khả thi khi tạo created_binary_file.php tạo các tệp nhị phân trong bộ nhớ.
SamStephens

11

Có một cách đơn giản hơn, tạo một biểu mẫu và đăng nó, điều này có nguy cơ đặt lại trang nếu loại mime trả lại là thứ mà trình duyệt sẽ mở, nhưng đối với csv và nó hoàn hảo

Ví dụ yêu cầu gạch dưới và jquery

var postData = {
    filename:filename,
    filecontent:filecontent
};
var fakeFormHtmlFragment = "<form style='display: none;' method='POST' action='"+SAVEAS_PHP_MODE_URL+"'>";
_.each(postData, function(postValue, postKey){
    var escapedKey = postKey.replace("\\", "\\\\").replace("'", "\'");
    var escapedValue = postValue.replace("\\", "\\\\").replace("'", "\'");
    fakeFormHtmlFragment += "<input type='hidden' name='"+escapedKey+"' value='"+escapedValue+"'>";
});
fakeFormHtmlFragment += "</form>";
$fakeFormDom = $(fakeFormHtmlFragment);
$("body").append($fakeFormDom);
$fakeFormDom.submit();

Đối với những thứ như html, văn bản và những thứ tương tự, hãy đảm bảo mimetype là một số thứ như application / octet-stream

Mã php

<?php
/**
 * get HTTP POST variable which is a string ?foo=bar
 * @param string $param
 * @param bool $required
 * @return string
 */
function getHTTPPostString ($param, $required = false) {
    if(!isset($_POST[$param])) {
        if($required) {
            echo "required POST param '$param' missing";
            exit 1;
        } else {
            return "";
        }
    }
    return trim($_POST[$param]);
}

$filename = getHTTPPostString("filename", true);
$filecontent = getHTTPPostString("filecontent", true);

header("Content-type: application/octet-stream");
header("Content-Disposition: attachment; filename=\"$filename\"");
echo $filecontent;

8

Tóm lại, không có cách nào đơn giản hơn. Bạn cần phải thực hiện một yêu cầu máy chủ khác để hiển thị tệp PDF. Mặc dù, có một vài lựa chọn thay thế nhưng chúng không hoàn hảo và sẽ không hoạt động trên tất cả các trình duyệt:

  1. Nhìn vào sơ đồ URI dữ liệu . Nếu dữ liệu nhị phân nhỏ thì có lẽ bạn có thể sử dụng javascript để mở cửa sổ truyền dữ liệu trong URI.
  2. Giải pháp duy nhất cho Windows / IE là có điều khiển .NET hoặc FileSystemObject để lưu dữ liệu trên hệ thống tệp cục bộ và mở nó từ đó.

Cảm ơn, tôi không biết về lược đồ URI dữ liệu. Có vẻ như đó có thể là cách duy nhất để thực hiện nó trong một yêu cầu duy nhất. Nhưng nó không thực sự là hướng tôi muốn đi.
Tauren

Do yêu cầu của khách hàng, cuối cùng tôi đã giải quyết vấn đề này bằng cách sử dụng các tiêu đề máy chủ trong phản hồi ( Content-Disposition: attachment;filename="file.txt"), nhưng tôi thực sự muốn thử phương pháp này vào lần tới. Tôi đã sử dụng URIdữ liệu cho hình thu nhỏ trước đây, nhưng tôi chưa bao giờ sử dụng nó để tải xuống - cảm ơn vì đã chia sẻ cái nugget này.
brichins

8

Đã được một thời gian kể từ khi câu hỏi này được hỏi nhưng tôi đã có cùng một thử thách và muốn chia sẻ giải pháp của mình. Nó sử dụng các yếu tố từ các câu trả lời khác nhưng tôi không thể tìm thấy nó hoàn toàn. Nó không sử dụng một biểu mẫu hoặc iframe nhưng nó yêu cầu một cặp yêu cầu bài đăng / nhận. Thay vì lưu tệp giữa các yêu cầu, nó sẽ lưu dữ liệu bài đăng. Nó dường như vừa đơn giản vừa hiệu quả.

khách hàng

var apples = new Array(); 
// construct data - replace with your own
$.ajax({
   type: "POST",
   url: '/Home/Download',
   data: JSON.stringify(apples),
   contentType: "application/json",
   dataType: "text",

   success: function (data) {
      var url = '/Home/Download?id=' + data;
      window.location = url;
   });
});

người phục vụ

[HttpPost]
// called first
public ActionResult Download(Apple[] apples)
{
   string json = new JavaScriptSerializer().Serialize(apples);
   string id = Guid.NewGuid().ToString();
   string path = Server.MapPath(string.Format("~/temp/{0}.json", id));
   System.IO.File.WriteAllText(path, json);

   return Content(id);
}

// called next
public ActionResult Download(string id)
{
   string path = Server.MapPath(string.Format("~/temp/{0}.json", id));
   string json = System.IO.File.ReadAllText(path);
   System.IO.File.Delete(path);
   Apple[] apples = new JavaScriptSerializer().Deserialize<Apple[]>(json);

   // work with apples to build your file in memory
   byte[] file = createPdf(apples); 

   Response.AddHeader("Content-Disposition", "attachment; filename=juicy.pdf");
   return File(file, "application/pdf");
}

1
Tôi nghĩ rằng tôi thích giải pháp này tốt nhất. Trong trường hợp của tôi mặc dù tôi đang tạo tệp, vì vậy tôi nghĩ rằng tôi sẽ thử giữ tệp trong bộ nhớ cho đến khi nó được truy cập và sau đó giải phóng bộ nhớ sau khi tải xuống để tôi không bao giờ phải ghi vào đĩa.
BVernon

5
$scope.downloadSearchAsCSV = function(httpOptions) {
  var httpOptions = _.extend({
    method: 'POST',
    url:    '',
    data:   null
  }, httpOptions);
  $http(httpOptions).then(function(response) {
    if( response.status >= 400 ) {
      alert(response.status + " - Server Error \nUnable to download CSV from POST\n" + JSON.stringify(httpOptions.data));
    } else {
      $scope.downloadResponseAsCSVFile(response)
    }
  })
};
/**
 * @source: https://github.com/asafdav/ng-csv/blob/master/src/ng-csv/directives/ng-csv.js
 * @param response
 */
$scope.downloadResponseAsCSVFile = function(response) {
  var charset = "utf-8";
  var filename = "search_results.csv";
  var blob = new Blob([response.data], {
    type: "text/csv;charset="+ charset + ";"
  });

  if (window.navigator.msSaveOrOpenBlob) {
    navigator.msSaveBlob(blob, filename); // @untested
  } else {
    var downloadContainer = angular.element('<div data-tap-disabled="true"><a></a></div>');
    var downloadLink      = angular.element(downloadContainer.children()[0]);
    downloadLink.attr('href', window.URL.createObjectURL(blob));
    downloadLink.attr('download', "search_results.csv");
    downloadLink.attr('target', '_blank');

    $document.find('body').append(downloadContainer);

    $timeout(function() {
      downloadLink[0].click();
      downloadLink.remove();
    }, null);
  }

  //// Gets blocked by Chrome popup-blocker
  //var csv_window = window.open("","","");
  //csv_window.document.write('<meta name="content-type" content="text/csv">');
  //csv_window.document.write('<meta name="content-disposition" content="attachment;  filename=data.csv">  ');
  //csv_window.document.write(response.data);
};

3

Không hoàn toàn là một câu trả lời cho bài viết gốc, mà là một giải pháp nhanh chóng và bẩn thỉu để đăng một đối tượng json lên máy chủ và tự động tạo ra một bản tải xuống.

JQuery phía khách hàng:

var download = function(resource, payload) {
     $("#downloadFormPoster").remove();
     $("<div id='downloadFormPoster' style='display: none;'><iframe name='downloadFormPosterIframe'></iframe></div>").appendTo('body');
     $("<form action='" + resource + "' target='downloadFormPosterIframe' method='post'>" +
      "<input type='hidden' name='jsonstring' value='" + JSON.stringify(payload) + "'/>" +
      "</form>")
      .appendTo("#downloadFormPoster")
      .submit();
}

..và sau đó giải mã chuỗi json ở phía máy chủ và đặt tiêu đề để tải xuống (ví dụ PHP):

$request = json_decode($_POST['jsonstring']), true);
header('Content-Type: application/csv');
header('Content-Disposition: attachment; filename=export.csv');
header('Pragma: no-cache');

Tôi thích giải pháp này. Trong câu hỏi của OP, có vẻ như người yêu cầu biết liệu có nên tải xuống tệp hoặc dữ liệu JSON hay không, vì vậy anh ta có thể quyết định ở cuối máy khách và đăng lên một URL khác, thay vì quyết định ở cuối máy chủ.
Sam

2

Tôi nghĩ cách tiếp cận tốt nhất là sử dụng kết hợp, Cách tiếp cận thứ hai của bạn dường như là một giải pháp tao nhã nơi các trình duyệt có liên quan.

Vì vậy, tùy thuộc vào cách cuộc gọi được thực hiện. (cho dù đó là trình duyệt hay cuộc gọi dịch vụ web), bạn có thể sử dụng kết hợp cả hai, với việc gửi URL tới trình duyệt và gửi dữ liệu thô tới bất kỳ ứng dụng khách dịch vụ web nào khác.


Cách tiếp cận thứ hai của tôi bây giờ cũng hấp dẫn hơn đối với tôi. Cảm ơn đã xác nhận nó là một giải pháp đáng giá. Bạn có gợi ý rằng tôi chuyển một giá trị bổ sung trong đối tượng json cho biết yêu cầu này đang được thực hiện từ trình duyệt dưới dạng cuộc gọi ajax thay vì cuộc gọi dịch vụ web không? Có một số cách để thực hiện điều này mà tôi có thể nghĩ ra, nhưng bạn sẽ sử dụng kỹ thuật nào?
Tauren

không thể được xác định bởi tiêu đề http của Tác nhân người dùng? Hoặc bất kỳ tiêu đề http khác?
naikus

1

Tôi đã thức được hai ngày nay để cố gắng tìm ra cách tải xuống một tệp bằng cách sử dụng jquery với cuộc gọi ajax. Tất cả các hỗ trợ tôi nhận được không thể giúp tình hình của tôi cho đến khi tôi thử điều này.

Phía khách hàng

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);
        }
    });

}

Phía máy chủ

 [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.
    }

Chúc may mắn.


2
Điều này sẽ làm việc, cho các tập tin nhỏ. Nhưng nếu bạn có một tệp lớn, bạn sẽ gặp phải vấn đề về url quá dài. Hãy thử với 1.000 bản ghi, nó sẽ phá vỡ và chỉ xuất một phần dữ liệu.
Michael Merrell

1

Tìm thấy nó ở đâu đó từ lâu và nó hoạt động hoàn hảo!

let payload = {
  key: "val",
  key2: "val2"
};

let url = "path/to/api.php";
let form = $('<form>', {'method': 'POST', 'action': url}).hide();
$.each(payload, (k, v) => form.append($('<input>', {'type': 'hidden', 'name': k, 'value': v})) );
$('body').append(form);
form.submit();
form.remove();

0

Một cách tiếp cận khác thay vì lưu tệp trên máy chủ và truy xuất tệp đó là sử dụng .NET 4.0+ ObjectCache với thời gian hết hạn ngắn cho đến khi hành động thứ hai (tại thời điểm đó có thể bị hủy hoàn toàn). Lý do mà tôi muốn sử dụng JQuery Ajax để thực hiện cuộc gọi, là vì nó không đồng bộ. Xây dựng tệp PDF động của tôi mất khá nhiều thời gian và tôi hiển thị hộp thoại spinner bận rộn trong thời gian đó (nó cũng cho phép các công việc khác được thực hiện). Cách tiếp cận sử dụng dữ liệu được trả về trong "thành công:" để tạo Blob không hoạt động đáng tin cậy. Nó phụ thuộc vào nội dung của tệp PDF. Nó dễ dàng bị hỏng bởi dữ liệu trong phản hồi, nếu nó không hoàn toàn bằng văn bản, đó là tất cả những gì Ajax có thể xử lý.


0

Giải pháp

Tệp đính kèm xử lý nội dung dường như hoạt động với tôi:

self.set_header("Content-Type", "application/json")
self.set_header("Content-Disposition", 'attachment; filename=learned_data.json')

Giải pháp thay thế

ứng dụng / octet-stream

Tôi đã có một cái gì đó tương tự xảy ra với tôi với JSON, đối với tôi ở phía máy chủ, tôi đang đặt tiêu đề thành self.set_header ("Kiểu nội dung", " application / json ") tuy nhiên khi tôi đổi nó thành:

self.set_header("Content-Type", "application/octet-stream")

Nó tự động tải xuống.

Cũng biết rằng để tệp vẫn giữ hậu tố .json, bạn sẽ cần nó trên tiêu đề tên tệp:

self.set_header("Content-Disposition", 'filename=learned_data.json')

-1

Với HTML5, bạn chỉ cần tạo một neo và nhấp vào nó. Không cần phải thêm nó vào tài liệu khi còn nhỏ.

const a = document.createElement('a');
a.download = '';
a.href = urlForPdfFile;
a.click();

Tất cả đã được làm xong.

Nếu bạn muốn có một tên đặc biệt để tải xuống, chỉ cần chuyển nó trong downloadthuộc tính:

const a = document.createElement('a');
a.download = 'my-special-name.pdf';
a.href = urlForPdfFile;
a.click();

4
câu hỏi là về phương pháp POST
dovid
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.