Dans mon application Vue, je reçois un PDF en tant que blob et je souhaite l'afficher à l'aide de la visionneuse PDF du navigateur.
Je le convertis en fichier et génère un objet URL:
const blobFile = new File([blob], `my-file-name.pdf`, { type: 'application/pdf' })
this.invoiceUrl = window.URL.createObjectURL(blobFile)
Ensuite, je l'affiche en définissant cette URL en tant qu'attribut data
d'un élément d'objet.
<object
:data="invoiceUrl"
type="application/pdf"
width="100%"
style="height: 100vh;">
</object>
Le navigateur affiche ensuite le PDF à l'aide du visualiseur PDF. Cependant, dans Chrome, le nom du fichier que je fournis (ici, mon-nom-fichier.pdf) n'est pas utilisé: je vois un hachage dans la barre de titre de la visionneuse PDF et lorsque je télécharge le fichier à l'aide de soit un clic droit -> Enregistrer sous ... ou les commandes du visualiseur, il enregistre le fichier avec le hachage du blob (cda675a6-10af-42f3-aa68-8795aa8c377d
ou similaire).
La visionneuse et le nom du fichier fonctionnent comme je l'avais espéré dans Firefox; c'est uniquement Chrome dans lequel le nom de fichier n'est pas utilisé.
Existe-t-il un moyen, à l'aide de Javascript natif (y compris ES6, mais pas de dépendances tierces autres que Vue), de définir le nom de fichier d'un élément blob/object dans Chrome?
[edit] Si cela vous aide, la réponse contient les en-têtes suivants:
Content-Type: application/pdf; charset=utf-8
Transfer-Encoding: chunked
Content-Disposition: attachment; filename*=utf-8''Invoice%2016246.pdf;
Content-Description: File Transfer
Content-Encoding: gzip
L'extension de Chrome semble reposer sur le nom de la ressource défini dans l'URI, c'est-à-dire le file.ext
dans protocol://domain/path/file.ext
.
Donc, si votre URI d'origine contient ce nom de fichier, le plus simple serait peut-être simplement de transformer la variable data
de votre <objet> en URI à partir duquel vous avez directement récupéré le fichier PDF, au lieu de suivre le style de Blob.
Dans certains cas, cela ne peut pas être fait et, pour ceux-ci, il existe une méthode convoluted, qui pourrait ne pas fonctionner dans les versions futures de Chrome, et probablement pas dans d'autres navigateurs, nécessitant de configurer un Travailleur de service .
Comme nous l'avons dit en premier lieu, Chrome analyse l'URI à la recherche d'un nom de fichier. Ce que nous devons faire, c'est donc avoir un URI, avec ce nom de fichier, qui pointe vers notre BlobURI.
Et pour pouvoir le faire, le seul moyen que j’ai trouvé pour le moment est de
src
d'un <iframe>1 à ce faux URI.1.Je ne pouvais pas voir les requêtes effectuées à partir d'une balise <object> dans Chrome, il est donc probablement préférable d'utiliser un iframe ici (cela aurait de meilleurs résultats dans IE également)).
Ou en code,
Dans 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);
})
}
Dans le 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))
}
});
Malheureusement, je n’ai pas pu faire fonctionner ServiceWorker sur plnkr.co, mais vous pouvez toujours trouver l’ensemble configuration ici que vous devriez pouvoir copier sur votre hôte local.
Et une autre solution, je n'ai pas pris le temps de vérifier par moi-même, serait de lancer votre propre visionneur de pdf.
Mozilla a rendu son plugin basé sur js pdf.js disponible, nous devrions donc pouvoir définir le nom du fichier (même si, encore une fois, je n’ai pas encore creusé là-bas).
Enfin, Firefox peut utiliser la propriété name
d'un objet File
sur lequel un blobURI pointe vers . Ainsi, même si ce n'est pas ce que l'OP a demandé, dans FF, il suffit
const file = new File([blob], filename);
const url = new URL(blob);
object.data = url;
Si vous demandez la ressource via votre propre serveur, vous pouvez utiliser l'en-tête de réponse Content-Disposition
pour transmettre le nom du fichier dans la réponse.
Content-Disposition: inline
Content-Disposition: attachment
Content-Disposition: attachment; filename="filename.jpg"
Vous pouvez le remplacer par votre nom de fichier et votre extension. Vous pouvez jeter un oeil à ce link pour explorer cet en-tête plus en fonction de vos besoins.
Dans Chrome, le nom de fichier est dérivé de l'URL. Par conséquent, tant que vous utilisez une URL de blob, la réponse courte est "Non, vous ne pouvez pas définir le nom de fichier d'un objet PDF affiché dans Chrome". Vous n'avez aucun contrôle sur l'UUID attribué à l'URL du blob et vous ne pouvez pas le remplacer par le nom de la page à l'aide de l'élément object
. Il est possible qu’à l’intérieur du PDF un titre soit spécifié et qu’il apparaisse dans le visualiseur PDF comme nom du document, mais que vous obteniez toujours le nom de hachage lors du téléchargement.
Cela semble être une mesure de sécurité, mais je ne peux pas le dire avec certitude.
Bien sûr, si vous avez le contrôle sur l'URL, vous pouvez facilement définir le nom de fichier PDF en modifiant l'URL.