СИТУАЦИЯ:
Интерфейс: Vue. Бэкэнд: Laravel.
Внутри веб-приложения мне нужно разрешить пользователю загружать определенные файлы pdf:
КОД:
API:
$file = public_path() . "/path/test.pdf";
$headers = [
'Content-Type' => 'application/pdf',
];
return response()->download($file, 'test.pdf', $headers);
Веб-приложение:
downloadFile() {
this.$http.get(this.apiPath + '/download_pdf')
.then(response => {
let blob = new Blob([response.data], { type: 'application/pdf' })
let link = document.createElement('a')
link.href = window.URL.createObjectURL(blob)
link.download = 'test.pdf'
link.click()
})
}
ИСХОД:
Используя этот код, мне удалось загрузить файл pdf. Проблема в том, что pdf пустой.
Каким-то образом данные были повреждены (не проблема этого конкретного файла pdf, я пробовал с несколькими файлами pdf - тот же результат)
ОТВЕТ С СЕРВЕРА:
Сам ответ от сервера в порядке:
PDF:
Проблема может быть в файле pdf. Это определенно выглядит поврежденными данными. Это отрывок того, как выглядит response.data:
ВОПРОС:
Как я могу правильно загрузить файл pdf, используя Laravel для API и Vue для веб-приложения?
Спасибо!



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Вы не сможете выполнить загрузку с Laravel на Vue, поскольку я предполагаю, что оба они работают на разных портах.
Даже если вы попробуете что-то подобное.
public function getDownload()
{
//PDF file is stored under project/public/download/info.pdf
$file= public_path(). "/download/info.pdf";
$headers = [
'Content-Type' => 'application/pdf',
];
return response()->download($file, 'filename.pdf', $headers);
}
Это не поможет, поскольку вы отправляете заголовки в порт Laravel. Попробуйте использовать библиотеки Vue js и попробуйте отправить этот PDF-контент в библиотеку.
Попробуй это Получите помощь отсюда
Конечно, дайте мне знать, сработало это или нет @johnnyfittizio
В предоставленной вами ссылке я нашел реальное решение. Все было правильно, за исключением того факта, что отсутствовал responseType. Axios или vue-ресурс значения не имеет. Я написал исправленный код в ответ. Я поблагодарил вас за то, что вы указали в правильном направлении. Спасибо!
РЕШЕНИЕ:
Код выше был правильным. Чего не хватало, так это добавления правильного responseType как arraybuffer.
Меня напугали те ???? внутри ответа, и это меня вводило в заблуждение.
Эти вопросительные знаки были нормальными, поскольку pdf - это двоичные данные, и их должен читать настоящий читатель.
ARRAYBUFFER:
А arraybuffer как раз используется для хранения двоичных данных.
Это определение с веб-сайта Mozilla:
The ArrayBuffer object is used to represent a generic, fixed-length raw binary data buffer. You cannot directly manipulate the contents of an ArrayBuffer; instead, you create one of the typed array objects or a DataView object which represents the buffer in a specific format, and use that to read and write the contents of the buffer.
А строка ResponseType указывает тип ответа. Сообщая ему массив массива, он обрабатывает данные соответствующим образом.
И просто добавив responseType, мне удалось правильно загрузить файл pdf.
КОД:
Это исправленный код Vue (точно так же, как и раньше, но с добавлением responseType):
downloadFile() {
this.$http.get(this.appApiPath + '/testpdf', {responseType: 'arraybuffer'})
.then(response => {
let blob = new Blob([response.data], { type: 'application/pdf' })
let link = document.createElement('a')
link.href = window.URL.createObjectURL(blob)
link.download = 'test.pdf'
link.click()
})
}
Обновлено:
Это более полное решение, учитывающее поведение других браузеров:
downloadContract(booking) {
this.$http.get(this.appApiPath + '/download_contract/' + booking.id, {responseType: 'arraybuffer'})
.then(response => {
this.downloadFile(response, 'customFilename')
}, response => {
console.warn('error from download_contract')
console.info(response)
// Manage errors
}
})
},
downloadFile(response, filename) {
// It is necessary to create a new blob object with mime-type explicitly set
// otherwise only Chrome works like it should
var newBlob = new Blob([response.body], {type: 'application/pdf'})
// IE doesn't allow using a blob object directly as link href
// instead it is necessary to use msSaveOrOpenBlob
if (window.navigator && window.navigator.msSaveOrOpenBlob) {
window.navigator.msSaveOrOpenBlob(newBlob)
return
}
// For other browsers:
// Create a link pointing to the ObjectURL containing the blob.
const data = window.URL.createObjectURL(newBlob)
var link = document.createElement('a')
link.href = data
link.download = filename + '.pdf'
link.click()
setTimeout(function () {
// For Firefox it is necessary to delay revoking the ObjectURL
window.URL.revokeObjectURL(data)
}, 100)
},
Большое спасибо @FrancescoMussi! Это очень полезно. Мой PDF-файл загружается, но не открывается или открывается с ошибкой, что его нельзя открыть. Когда я добавил responseType, все заработало!
responseType как arraybuffer! Работы <3
Я уже два дня работаю над потоковой передачей данных в формате PDF, выдергиваю волосы. Я продолжаю получать данные в формате PDF "undefined". Я вижу чертовы PDF-данные в сети, но почему-то не могу их сохранить!
downloadFile: function () {
this.$http.post('{{ route('download.download') }}', {
_token: "{{ csrf_token() }}",
inputs: this.inputs
},{responseType: 'arraybuffer'}).then(response => {
var filename = response.headers.get('content-disposition').split('=')[1].replace(/^\"+|\"+$/g, '')
var url = window.URL.createObjectURL(new Blob([response.body],{type:response.headers.get('content-type')}))
var link = document.createElement('a')
link.href = url
link.setAttribute('download', filename)
document.body.appendChild(link)
link.click()
});
},
Добавьте обсуждение к своему ответу, чтобы объяснить, как он решает вопрос ОП.
Для Vue 2.5.22 и Vue-ресурса 1.5.1
это работает для меня.
из бэкэнда laravel:
$pdf = PDF::loadView('your_view_name', ['data' => $data]);
return $pdf->output();
из интерфейса vuejs:
axios({
url: 'http://localhost:8000/api/your-route',
method: 'GET',
responseType: 'blob',
}).then((response) => {
var fileURL = window.URL.createObjectURL(new Blob([response.data]));
var fileLink = document.createElement('a');
fileLink.href = fileURL;
fileLink.setAttribute('download', 'file.pdf');
document.body.appendChild(fileLink);
fileLink.click();
});
Выглядит очень похоже. Я попробую использовать Axios вместо vue-resource.