programing

JSON 데이터와 함께 POST를 통해 파일을 다운로드하는 JavaScript/jQuery

projobs 2023. 2. 3. 21:27
반응형

JSON 데이터와 함께 POST를 통해 파일을 다운로드하는 JavaScript/jQuery

저는 jquery 기반의 한 페이지 웹 앱을 가지고 있습니다.AJAX 콜을 통해 RESTful Web 서비스와 통신합니다.

다음 사항을 달성하려고 합니다.

  1. JSON 데이터를 포함한 POST를 REST URL로 송신합니다.
  2. 요구가 JSON 응답을 지정하면 JSON이 반환됩니다.
  3. 요구가 PDF/XLS/etc 응답을 지정하면 다운로드 가능한 바이너리가 반환됩니다.

현재 1과 2가 작동하고 있으며 클라이언트 jquery 앱은 JSON 데이터를 기반으로 DOM 요소를 생성하여 웹 페이지에 반환된 데이터를 표시합니다.웹 서비스의 관점에서 작업하는 #3도 있습니다.즉, 올바른 JSON 파라미터를 지정하면 바이너리 파일이 생성되어 반환됩니다.하지만 클라이언트 Javascript 코드의 #3을 처리하는 최선의 방법은 잘 모르겠습니다.

이와 같이 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를 생성하여 서버에 저장하고 URL이 포함된 JSON을 파일에 반환하는 것입니다.그런 다음 ajax 성공 핸들러에서 다른 콜을 발행하여 다음과 같은 작업을 수행합니다.

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

그러나 그렇게 하려면 서버에 여러 번 콜을 해야 합니다.서버는 다운로드 가능한 파일을 작성하고 어딘가에 저장한 후 정기적으로 스토리지 영역을 청소해야 합니다.

이것을 달성할 수 있는 더 간단한 방법이 있을 것이다.아이디어?


문서를 은 $.ajax 데이터 유형 중 하나밖에 할 수 .xml, html, script, json, jsonp, text따라서 @VinayC 답변에서 제시한 데이터 URI 스킴을 사용하여 바이너리 파일을 삽입하지 않는 한 Ajax 요청을 사용하여 파일을 직접 다운로드할 방법은 없을 것입니다.

그래서 다음 옵션을 선택할 수 있습니다.

  1. ajax를 사용하지 말고 폼 포스트를 제출하고 JSON 데이터를 폼 값에 포함시킵니다.숨겨진 iframes 등을 조작할 필요가 있을 것입니다.

  2. ajax를 사용하지 않고 JSON 데이터를 쿼리 문자열로 변환하여 표준 GET 요청을 작성하고 window.location을 설정합니다.href는 이 URL입니다.클릭 핸들러에서 event.proventDefault()를 사용하여 브라우저가 응용 프로그램 URL에서 변경되지 않도록 해야 합니다.

  3. 위의 다른 아이디어를 사용하되 @naikus 답변의 제안으로 강화하십시오.웹 서비스가 AJAX 콜을 통해 호출되었음을 알 수 있도록 AJAX 요청을 몇 가지 매개 변수와 함께 전송합니다.웹 서비스가 Ajax 콜에서 호출된 경우 생성된 리소스에 URL을 포함한 JSON을 반환하기만 하면 됩니다.리소스가 직접 호출된 경우 실제 이진 파일을 반환합니다.

생각할수록 마지막 선택지가 마음에 들어요.이렇게 하면 요청에 대한 정보(생성 시간, 파일 크기, 오류 메시지 등)를 얻을 수 있으며 다운로드를 시작하기 전에 해당 정보에 대해 조치를 취할 수 있습니다.단점은 서버상의 추가 파일 관리입니다.

다른 방법은 없나요?이 방법에 대해 알아야 할 장단점이 있습니까?

Letronje의 솔루션은 매우 간단한 페이지에서만 작동합니다. document.body.innerHTML +=HTML을 을 iframe HTML로 합니다.HTML 입니다.에 의해 됩니다.페이지에 있는 이벤트 바인딩 및 다른 바인딩이 삭제됩니다.하여 " " " 를 사용합니다.appendChild★★★★★★ 。

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

또는 jQuery 사용

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

실제 기능: postData 변수 내의 데이터로 /create_binary_file.php에 투고를 수행합니다.투고가 정상적으로 완료되면 페이지 본문에 새로운 iframe을 추가합니다./create_binary_file.php로부터의 응답에 값 'url'이 포함되는 것을 전제로 하고 있습니다.이 값은 생성된 PDF/XLS/etc 파일을 다운로드할 수 있는 URL입니다.이 URL을 참조하는 페이지에 iframe을 추가하면 웹 서버가 적절한 MIME 유형 설정을 가지고 있다고 가정하여 브라우저가 사용자에게 파일을 다운로드하도록 승격됩니다.

블럽을 사용하는 다른 옵션을 가지고 놀고 있습니다.간신히 텍스트 문서를 다운로드 할 수 있었습니다.PDF도 다운로드했습니다(단, 파손되어 있습니다).

blob API를 사용하여 다음을 수행할 수 있습니다.

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

});

IE 10+, Chrome 8+, FF 4+ 입니다.https://developer.mozilla.org/en-US/docs/Web/API/URL.createObjectURL 를 참조해 주세요.

Chrome, Firefox 및 Opera에서만 파일을 다운로드합니다.그러면 앵커 태그의 다운로드 속성이 브라우저에 강제로 다운로드됩니다.

좀 오래된 건 알지만 좀 더 우아한 해결책을 생각해 낸 것 같아요.나도 똑같은 문제가 있었어.제안되는 솔루션과 관련된 문제점은 모두 서버에 파일을 저장해야 하는데, 다른 문제가 발생했기 때문에 서버에 파일을 저장하고 싶지 않았습니다(보안: 인증되지 않은 사용자가 파일에 액세스할 수 있는 경우, 정리: 파일을 삭제하는 방법 및 시기).그리고 제 데이터도 당신과 마찬가지로 복잡하고 중첩된 JSON 오브젝트여서 폼에 넣기가 어려웠습니다.

저는 두 개의 서버 기능을 만들었습니다.첫 번째는 데이터를 검증했습니다.오류가 있으면 반환됩니다.에러가 아닌 경우 serialize/encode된 파라미터는 모두 base64 문자열로 반환했습니다.그리고 클라이언트에서는 입력이 1개만 숨겨져 있고, 2번째 서버 기능에 투고하는 폼이 있습니다.숨겨진 입력을 base64 문자열로 설정하고 포맷을 전송합니다.두 번째 서버 함수는 파라미터를 디코딩/비직렬화하고 파일을 생성합니다.폼은 페이지의 새 창 또는 iframe으로 전송될 수 있으며 파일이 열립니다.

더 많은 작업이 수반되고 더 많은 처리가 이루어질 수 있지만, 전반적으로 이 솔루션을 통해 훨씬 더 기분이 좋아졌습니다.

코드는 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);
    }

고객으로

    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
    }

보다 심플한 방법으로 폼을 작성하여 투고할 수 있습니다.이것은 반환되는 MIME 타입이 브라우저에 열려 있는 경우 페이지를 리셋할 위험이 있지만 CSV에 대해서는 완벽합니다.

예에는 밑줄과 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();

html, text 등의 경우 mimtype이 application/octet-stream과 같은 것임을 확인합니다.

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;

이 질문이 나온지 꽤 되었지만, 저는 같은 도전을 했고 저의 해결책을 공유하고 싶습니다.다른 답변의 요소를 사용하고 있습니다만, 그 전체를 찾을 수 없었습니다.폼이나 iframe은 사용하지 않지만 post/get 요청 쌍이 필요합니다.요청 간에 파일을 저장하는 대신 게시 데이터를 저장합니다.간단하면서도 효과적인 것 같아요.

고객

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

서버

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

간단히 말해서, 더 간단한 방법은 없다.PDF 파일을 표시하려면 다른 서버 요청을 해야 합니다.그러나 몇 가지 대안이 있지만 완벽하지는 않고 모든 브라우저에서 작동하지는 않습니다.

  1. 데이터 URI 스킴을 확인합니다.바이너리 데이터가 작을 경우 javascript를 사용하여 URI에서 데이터를 전달하는 창을 열 수 있습니다.
  2. Windows/IE만의 솔루션은, 를 사용하는 것입니다.NET 컨트롤 또는 FileSystemObject를 사용하여 로컬 파일 시스템에 데이터를 저장하고 거기에서 엽니다.

원래 투고에 대한 완전한 답변이 아니라 서버에 json 객체를 게시하고 다운로드를 동적으로 생성하기 위한 빠르고 더러운 솔루션입니다.

클라이언트 측 jQuery:

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

..그리고 서버측에서 json-string을 디코딩하여 다운로드용 헤더를 설정합니다(PHP 예).

$request = json_decode($_POST['jsonstring']), true);
header('Content-Type: application/csv');
header('Content-Disposition: attachment; filename=export.csv');
header('Pragma: no-cache');
$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);
};

최적의 접근법은 조합을 사용하는 것이라고 생각합니다만, 두 번째 접근법은 브라우저와 관련된 우아한 솔루션인 것 같습니다.

통화 방법에 따라 다릅니다.(브라우저인지 웹 서비스 콜인지에 관계없이) 2개의 조합을 사용하여 브라우저에 URL을 전송하고 다른 웹 서비스 클라이언트에 원시 데이터를 전송할 수 있습니다.

오래전에 어디선가 찾았는데 완벽하게 작동하더군요!

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

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

행운을 빌어요.

서버에 파일을 보존해 취득하는 대신에, 를 사용하는 방법도 있습니다.두 번째 액션(이 시점에서 확실하게 덤프할 수 있음)까지 짧은 기간 동안 만료되는 NET 4.0+ ObjectCache.JQuery Ajax를 사용하여 콜을 실행하는 이유는 비동기이기 때문입니다.다이나믹 PDF 파일을 작성하려면 시간이 많이 걸리고, 그 사이에 비지 스피너 다이얼로그가 표시됩니다(다른 작업도 가능합니다)."success:"에서 반환된 데이터를 사용하여 Blob을 생성하는 방법은 안정적으로 작동하지 않습니다.PDF 파일의 내용에 따라 다릅니다.Ajax가 처리할 수 있는 모든 텍스트가 아닌 경우 응답 데이터에 의해 쉽게 손상됩니다.

솔루션

콘텐츠 삭제 첨부 파일은 나에게 효과가 있는 것 같습니다.

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

회피책

응용 프로그램/옥텟 스트림

서버측에서는 헤더를 self로 설정하고 있었습니다만, JSON과 같은 일이 있었습니다.set_header("Content-Type", "application/json") 단, 변경 시 다음과 같이 표시됩니다.

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

자동으로 다운받았어요.

또한 파일이 .json 서픽스를 계속 유지하려면 파일 이름 헤더에 .json 서픽스를 저장해야 합니다.

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

독자적인 이벤트 작성에 관한 문제

이 문서에서 제안하는 솔루션의 대부분은 JavaScript를 비동기적으로 실행하고 링크 요소를 작성한 후 호출합니다.

const a = documet.createElement("a") 
a.click()

또는 마우스 이벤트 생성

new MouseEvent({/* ...some config */})

이거 괜찮겠죠?이게 뭐가 잘못됐나요?

이벤트 소싱이란?

이벤트 소싱은 클라우드 기반 아키텍처의 pub 서브 시스템이나 브라우저 api EventSource와 같은 컴퓨팅 전반에 걸쳐 많은 의미를 가집니다.브라우저의 컨텍스트에서는 모든 이벤트에는 소스가 있으며 해당 소스에는 이 이벤트를 시작한 사용자(사용자 또는 사이트)를 나타내는 숨겨진 속성이 있습니다.

이를 통해 두 번의 클릭 이벤트가 동일하지 않은 이유를 이해할 수 있습니다.

user click*          new MouseEvent()
-----------            -----------
| Event 1 |            | Event 2 |
-----------            -----------
     |                      |     
     |----------------------|
                 |
                 |
      ----------------------
      | Permissions Policy |    Available in chrome allows the server to control
      ----------------------    what features are going to be used by the JS
                 |
                 |
   ----------------------------
   | Browser Fraud Protection | The Browser REALLY doesnt like being told to pretend
   ---------------------------- to be a user. If you will remember back to the early
                 |              2000s when one click spun off 2000 pop ups. Well here
                 |              is where popups are blocked, fraudulent ad clicks are
                \ /             thrown out, and most importantly for our case stops 
                 v              fishy downloads
      JavaScript Event Fires

그래서 바보 같은 POST를 다운로드 할 수 없다

아니, 물론 넌 할 수 있어.사용자에게 이벤트를 생성할 수 있는 기회를 주기만 하면 됩니다.다음은 명백한 사용자 흐름 생성에 사용할 수 있는 패턴으로 부정 플래그가 부착되지 않은 패턴을 보여 줍니다.(jsx sorry not sorry 사용)

양식을 사용하여 포스트 액션이 있는 URL로 이동할 수 있습니다.

const example = () => (
  <form
   method="POST"
   action="/super-api/stuff"
   onSubmit={(e) => {/* mutably change e form data but don't e.preventDetfault() */}}
  >
    {/* relevant input fields of your download */}
  </form>
)

프리로드 다운로드가 설정 불가능한 경우 다운로드의 프리로드(pre-loading)를 고려할 수 있습니다.resp.blob() ★★★★★★★★★★★★★★★★★」new Blob(resp)이 명령어는 브라우저에 파일이며 이 파일에 대해 문자열 조작을 수행하지 않음을 나타냅니다.로 ''를 사용하시면 .window.URL.createObjectURL되어 있지

create Object(작성 객체)URL에서 Javascript 메모리 누수가 발생할 수 있음원천

만약 당신이 C++ 불량배들이 당신을 놀리는 것을 원하지 않는다면 당신은 이 기억을 없애야 한다.아, 하지만 난 그저 쓰레기 수집기를 좋아하는 호비스트야.대부분의 프레임워크에서 작업하는 경우(내 반응은) 컴포넌트와 권리에 대한 청소 효과를 비로 등록하기만 하면 됩니다.

const preload = () => {
  const [payload, setPayload] = useState("")
  
  useEffect(() => {
    fetch("/super-api/stuff")
      .then((f) => f.blob())
      .then(window.URL.createObjectURL)
      .then(setPayload)

    return () => window.URL.revokeObjectURL(payload)
  }, [])


  return (<a href={payload} download disabled={payload === ""}>Download Me</a>)
}

가까워진 것 같습니다만, 뭔가 파일(이미지)을 손상시키고 있습니다.어쨌든, 이 어프로치의 문제를 밝혀낼 수 있는 사람이 있을지도 모릅니다.

$.ajax({
            url: '/GenerateImageFile',
            type: 'POST',
            cache: false,
            data: obj,
            dataType: "text",
            success: function (data, status, xhr) {
                let blob = new Blob([data], { type: "image/jpeg" });

                let a = document.createElement('a');
                a.href = window.URL.createObjectURL(blob);
                a.download = "test.jpg";
                document.body.appendChild(a);
                a.click();
                document.body.removeChild(a);
                window.URL.removeObjectURL(a.href);
            },
            complete: function () {

            },
            beforeSend: function () {

            }
        });

나는 프랭크의 아이디어가 마음에 들어 나만의 반전을 하기로 결심했다.한 번에 하는 것은 매우 복잡하기 때문에, 2개의 포스트 방식을 사용하고 있습니다만, 데이터베이스를 한 번만 치면 완료되었을 때 파일을 저장하거나 정리할 필요가 없습니다.

먼저 Ajax 요청을 실행하여 데이터를 가져오지만 컨트롤러에서 데이터를 반환하는 대신 레코드의 TempData 스토리지에 연결된 GUID를 반환합니다.

$.get("RetrieveData", { name: "myParam"} , function(results){
    window.location = "downloadFile?id=" + results
});

public string RetrieveData(string name)
{
    var data = repository.GetData(name);
    string id = Guid.NewGuid().ToString();
    var file = new KeyValuePair<string, MyDataModel>(name, data);
    TempData[id]=file;
    return id;
}

그런 다음 window.location을 호출하면 새로운 메서드에 GUID를 전달하고 TempData에서 데이터를 가져옵니다.이 메서드가 실행되면 TempData는 무료가 됩니다.

public ActionResult DownloadFile(string id)
{
   var file = (KeyValuePair<string,MyDataModel>)TempData[id];
   var filename = file.Key;
   var data = file.Value;
   var byteArray = Encoding.UTF8.GetBytes(data);
   ...
   return File(byteArray, "text/csv", "myFile.csv");
}

HTML5에서는 앵커만 만들어 클릭하면 됩니다.아이로 문서에 추가할 필요가 없습니다.

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

다 했어요.

다운로드에 특별한 이름을 붙이려면 다음 웹 사이트에서 전달해 주세요.download속성:

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

언급URL : https://stackoverflow.com/questions/3499597/javascript-jquery-to-download-file-via-post-with-json-data

반응형