Расширение Chrome зависит от имени ресурса , заданного в URI, то есть file.ext
в protocol://domain/path/file.ext
.
Так что, если ваш исходный URIсодержит это имя файла, проще всего было бы просто сделать ваши s data
для URI, из которого вы получили pdf напрямую, вместо того, чтобы идти по пути Blob.
Теперь есть случаи, когда это невозможно сделать, и для них есть извилистый способ , который может не работать в будущих версиях Chrome и, вероятно, не в других браузерах.требуя установить Service Worker .
Как мы впервые сказали, Chrome анализирует URI в поисках имени файла, поэтому нам нужно иметь URI сэто имя файла, указывающее на наш BlobURI.
И чтобы сделать это, единственный способ, который я нашел на данный момент, это
- . Из документа сделайте запрос POST,который отправит BLOB-объект нашему ServiceWorker.
- Из ServiceWorker кэшируйте отправленный BLOB-объект
- Кадр из ServiceWorker, верните новый поддельный URI, который мы сопоставим с BLOB-объектомкэшируется в 2.
- Из документа установите
src
- Из негоServiceWorker, перехватите запрос и отправьте вместо этого наш кэшированный BLOB-объект.
- Из документа наслаждайтесь.
1. Я не смог увидеть запросы, сделанные из тега в Chrome, поэтому, вероятно, лучше использовать здесь iframe (будет лучший результатв IE тоже все равно).
или в коде
в document.html
// register our ServiceWorker
navigator.serviceWorker.register('/sw.js')
.then(...
...
function displayRenamedPDF(file, filename) {
// we use an hard-coded fake path
// that we will check in every requests from the SW
const reg_path = '/nameForcer_register/'
// pass the filename
const url = reg_path + encodeURIComponent(filename);
const xhr = new XMLHttpRequest();
xhr.open('POST', url);
return new Promise((res, rej) => {
xhr.onload = e => {
const frame = document.createElement('iframe');
frame.src = xhr.response;
document.body.append(frame);
return frame;
};
xhr.send(file);
})
}
в ServiceWorker sw.js
self.addEventListener('fetch', function(event) {
const req = event.request,
url = new URL(req.url),
// parse the /path/ from every request url
pathes = url.pathname.split('/'),
// are we registering
nameRegIndex = pathes.indexOf('nameForcer_register'),
// or fetching
nameFetcherIndex = pathes.indexOf('nameForcer_fetch');
if(nameRegIndex > -1) { // register
event.respondWith(
req.blob() // grab the POSTed Blob
.then((blob) => {
const filename = pathes[nameRegIndex+1] || '';
// store in our db object
db[filename] = blob;
return filename;
})
.then((filename) =>
new Response('/nameForcer_fetch/' + filename)
)
);
}
else if(nameFetcherIndex > -1) { // fetch
const filename = pathes[nameFetcherIndex + 1];
const cached = db[filename];
// just for Firefox, Chrome doesn't care...
const headers = new Headers({
'Content-Disposition': 'inline; filename="' + decodeURIComponent(filename) + '"'
});
event.respondWith(
new Response(cached, {
headers: headers
})
);
delete db[filename]; // !! one time URI !!
}
else { // normal requests
event.respondWith(fetch(event.request))
}
});
Я, к сожалению, не смог заставить ServiceWorker работать на plnkr.co, но вы все равно можете найти всю настройку здесь , что вам следуетбыть в состоянии скопировать на ваш локальный хост.
И еще одно решение, которое я сам не потратил на проверку, - это запустить собственный просмотрщик PDF.
Mozillaсделал доступным свой плагин на основе js pdf.js , поэтому оттуда мы сможем установить имя файла (хотя я еще не копал там).
И, наконец, Firefox может использовать свойство name
объекта File
, на который указывает blobURI.Так что, хотя это не то, о чем просил OP, в FF все, что требуется, это
const file = new File([blob], filename);
const url = new URL(blob);
object.data = url;