xlsx ファイルをダウンロードする際に、この小さな問題があります。jquery Ajaxを介してファイルのリクエストを送信していますが、バックエンドでデータが正しく収集され、xlsxファイルにアセンブルされています。そのため、フロントエンドに戻る途中で、ファイルを強制的にダウンロードする準備としてすべてのヘッダーを設定していますが、ダウンロードが開始されません。
これらは私のリクエストの応答ヘッダーです:
Connection Keep-Alive
Content-Disposition attachment; filename="export.xlsx"
Content-Length 346420
Content-Type application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
Date Mon, 23 Nov 2015 13:23:30 GMT
Keep-Alive timeout=5, max=91
Server Apache/2.4.16 (Win32) OpenSSL/1.0.1p PHP/5.6.12
Set-Cookie <cookiesettings>
content-transfer-encoding binary
x-powered-by PHP/5.6.12
ダウンロードはすぐに開始されるはずですが、何も起こりません。
編集: 今まではフォーム送信を使用していましたが、データ量が非常に多いため、ファイルの組み立てに必要な時間も非常に長く、場合によっては数分または 1 時間かかることもあり、これができなくなりました。
そこで、ファイルをビルドし、約 1 秒ごとに完了を要求する ajax スニペットを開始する Java ジョブを作成しました。
これが私のコードです。フロントエンド: これはボタンクリックで呼び出されます
download: function (type, maximum) {
var
self = this,
oParams = this.oTable.oApi._fnAjaxParameters(this.oTable.fnSettings()),
aoPost = [
{ 'name': 'exportType', 'value': type },
{ 'name': 'exportMax', 'value': maximum },
{ 'name': 'handleId', 'value': self.options.handleId }
],
nIFrame, nContentWindow, nForm, nInput, i
;
// Call a self made function to get extra search parameters
// without call an data update AJAX call.
self.oTable.fnSettings().addAdditionalSearchData(oParams);
// Create an IFrame to do the request
nIFrame = document.createElement('iframe');
nIFrame.setAttribute('id', 'RemotingIFrame');
nIFrame.style.border = '0px';
nIFrame.style.width = '0px';
nIFrame.style.height = '0px';
document.body.appendChild(nIFrame);
nContentWindow = nIFrame.contentWindow;
nContentWindow.document.open();
nContentWindow.document.close();
nForm = nContentWindow.document.createElement('form');
nForm.className = 'export-table';
nForm.setAttribute('method', 'post');
// Add POST data.
var formData = {};
for (i = 0; i < aoPost.length; i++) {
nInput = nContentWindow.document.createElement('input');
nInput.setAttribute('name', aoPost[ i ].name);
nInput.setAttribute('type', 'text');
nInput.value = aoPost[ i ].value;
nForm.appendChild(nInput);
formData[aoPost[ i ].name] = aoPost[ i ].value;
}
// Add dataTables POST.
for (i = 0; i < oParams.length; i++) {
nInput = nContentWindow.document.createElement('input');
nInput.setAttribute('name', oParams[ i ].name);
nInput.setAttribute('type', 'text');
nInput.value = oParams[ i ].value;
nForm.appendChild(nInput);
formData[oParams[ i ].name] = oParams[ i ].value;
}
nForm.setAttribute('action', '/service/exportTableData');
// Add the form and the iFrame.
nContentWindow.document.body.appendChild(nForm);
// Send the request.
//nForm.submit();
// Send the request.
var form = $(nContentWindow.document.body).find('form.export-table');
var jobId = 0;
form.ajaxForm(
{
'showMessagesOnSuccess': false
},
{
'getData': function () {
return formData;
}
}
).data('ajaxForm').submit();
}
送信時の Ajax リクエスト:
$.ajax({
type: 'POST',
url: self.handler.getServiceUrl(),
timeout: GLOBALS.AJAX_REQUEST_TIMEOUT,
cache: false,
data: (<get the Data>)
,
success: function (response) {
if (response.success === true) {
// Check if we have to wait for a result.
if (response.jobId !== undefined && response.jobId !== 0) {
self.checkJobStatus(response.jobId);
} else {
<success - show some messages>
}
} else {
self.handler.error(response);
}
},
error: function () {
<Show error Message>
}
});
CheckJobStatus:
checkJobStatus: function (jobId) {
var self = this;
$.ajax({
type: 'POST',
timeout: GLOBALS.AJAX_REQUEST_TIMEOUT,
cache: false,
data: { 'jobId': jobId },
url: self.handler.getServiceUrl(),
success: function (response) {
if(response !== null && response.data !== undefined) {
if (response.data.isFinished === true) {
if (response.success === true) {
// Check if we have to wait for a result.
self.handler.success(response);
} else {
self.handler.error(response);
}
} else if (response.success === true && response.data !== null) {
setTimeout(
function () {
self.checkJobStatus(jobId);
},
500
);
} else {
Helper.logFrontendError();
}
} else if (response !== null && response.success === true) {
setTimeout(
function () {
self.checkJobStatus(jobId);
},
1000
);
} else {
Helper.logFrontendError();
}
},
error: function (response) {
Helper.logFrontendError();
}
});
}
バックエンド - php:
(...)
if ($action == 'exportTableData' || $action == 'exportChartData') {
$responseData = $service->execute();
if(isset($responseData->data['contentType']) && $responseData->data['contentType'] != null && isset($responseData->data['data'])) {
$this->sendTextData($responseData->data['contentType'], $responseData->data['data']);
} else {
$this->sendJsonData($responseData);
}
} else {
$this->sendJsonData($service->execute());
}
(...)
private function sendTextData($contentType, $data) {
$this->set('filename', 'export.xlsx');
$this->set('data', $data);
$this->response->type($contentType);
$this->render('/Layouts/excel', 'excel');
}
(...)
$handlerResult = new HandlerResult();
if($dataServiceResult == null) {
$service = new DataService();
$dataServiceResult = $service->exportTableData(
$controller->Auth->User('id'),
json_encode($request->data),
null
);
} else {
if ($dataServiceResult->header->resultKey == 0) {
$handlerResult->wsData['data'] = $dataServiceResult->data;
$handlerResult->wsData['contentType'] = $dataServiceResult->contentType;
}
}
$handlerResult->wsResultHeader = $dataServiceResult->header;
return $handlerResult; // ++++ this result returns to the first codeblock in this section ++++
バックエンド - Java - ファイルがアセンブルされる場所:
(...)
if (jobId > 0) {
FrontendJobStatus status = FrontendJobQueue.getJobStatus(context.userId, jobId);
this.result = (WSExportTableDataResult) status.getResult();
logger.info((this.result.data == null) ? "ByteArray is EMPTY" : "ByteArray is NOT EMPTY");
} else {
this.jobId = FrontendJobQueue.addJob(this.context.userId, new ExportTableDataJob(this.context, this.postData));
this.result.header.jobId = this.jobId;
}
(...)
The Jop:
<Workbook assembly>
ByteArrayOutputStream out = new ByteArrayOutputStream();
wb.write(out);
this.result.data = out.toByteArray();
this.result.contentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
// this.result.contentType = "application/vnd.ms-excel";
this.result.setResultHeader(APIConstants.RESULT_SUCCESS);
レイアウト/エクセル:
<?php
header('Content-Disposition: attachment; filename="'.$filename.'"');
header('Content-Transfer-Encoding: binary');
ob_clean();
echo $data;
編集 2: データの成功時に新しいウィンドウを開こうとしたところ、ダウンロードを開始できましたが、ファイルは有効な xlsx ファイルではなくなりました。
var reader = new FileReader();
var blob = new Blob([response.responseText], { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" });
reader.readAsDataURL(blob);
reader.onloadend = function (e) {
window.open(reader.result, 'Excel', 'width=20,height=10,toolbar=0,menubar=0,scrollbars=no', '_blank');
}
何か案は?