В этой статье рассказывается о некоторых знаниях, связанных с загрузкой файлов через интерфейс.
Когда дело доходит до загрузки файлов на переднем конце, первое, о чем я думаю, это то, что когда я учился в школе, я сам построил среду nginx + php, а затем открыл страницуhttp://localhost:80/index.php
, Но странно обнаружить, что каждый раз, когда вы его открываете, он становится загрузкой файла.
Позже я узнал, что заголовок запроса будет содержатьAccept
поле, в заголовке ответа будетContent-Type
поле, первое используется, чтобы сказатьS
Какие типы контента может принять клиент, рассказывает последнийC
Какой тип контента возвращается с терминала.
MIME
MIME— это стандартизированный способ представления характера и формата документа, и браузеры обычно используют MIME для определения типа (а не расширения файла).
Content-type использует типы MIME, соответствующие файлам jpg.image/jpeg
, файл js соответствуетapplication/javascript
, xlsx этоapplication/vnd.openxmlformats-officedocument.spreadsheetml.sheet
.
MIME имеет два типа по умолчанию:
-
text/plain
Представляет значение по умолчанию для текстовых файлов. Текстовый файл должен быть удобочитаемым и не содержать двоичных данных. -
application/octet-stream
Указывает значение по умолчанию для всех остальных случаев. Неизвестный тип файла должен использовать этот тип.
👆index.php
Причина, по которой это станет загрузкой файла, заключается в том, что я неправильно разобрал файл php из-за ошибки установки, а nginx напрямую обращается к файлу и добавляет contentType по умолчаниюapplication/octet-stream
. Потому что Chrome не может выполнитьapplication/octet-stream
Отформатируйте файлы, операция по умолчанию заключается в их загрузке (разные браузеры выполняют разные операции с файлами, которые не могут быть обработаны, и некоторые браузеры будут пытаться обнюхать).
Это также объясняет, почему мы напрямую обращаемся кhttps://xxx/foo/bar.zip
При ожидании ресурса браузер загружает его напрямую.
Вставьте класс безопасности:
Когда сервер возвращает тип MIME, который не поддерживается браузером, некоторые браузеры попытаются его обнюхать и помочь нерадивому разработчику исправить ошибку, но это может привести к атаке на ваш сайт. Например, пользователь загружает изображение гигантской панды со следующим содержанием:
На самом деле это файл html, но суффикс написан как jpeg для загрузки. В это время, если сервер не устанавливает contentType, он напрямую считывает файл и возвращает его во внешний интерфейс.
# koa router 演示代码
router.get('/assets/:file.jpeg', (ctx) => {
ctx.body = fs.createReadStream(`./public/assets/${ctx.params.file}.jpeg`);
});
Браузер из лучших побуждений получает MIME-тип как application/octet-stream, а затем читает содержимое и находит, а, это html, мы должны показать его напрямую. 🌚🌚🌚
Когда пользователь увидел милую панду, он также сообщил хакеру свои личные данные.
Чтобы избежать подобных инцидентов с безопасностью, установите
- Добавьте соответствующий тип содержимого к возвращаемому содержимому.
- добавить заголовки ответа
X-Content-Type-Options: nosniff
, чтобы браузер не пытался нюхать
router.get('/assets/:file.jpeg', (ctx) => {
ctx.type = 'image/jpeg';
ctx.set('X-Content-Type-Options', 'nosniff');
ctx.body = fs.createReadStream(`./public/assets/${ctx.params.file}.jpeg`);
});
Только в демонстрационных целях koa следует использовать для предоставления услуг статических ресурсов.koa-static
и другие пакеты с открытым исходным кодом, они автоматически добавят contentType.
Как заставить браузер загружать изображения
Вышеупомянутые типы документов, которые не поддерживаются соответствующим браузером, будут загружены по умолчанию. А как насчет тех типов, которые можно обрабатывать? Такие как картинки, js, json и другой контент?
Взяв в качестве примера json, поскольку браузер умеет его анализировать, содержимое json будет напечатано на странице.
Что, если требуется разрешить пользователям загружать файлы json?
Есть еще один поле заголовка ответаConten-disposition
👹, ответ Content-Disposition на содержимое указанной формы, которая связана с формой (которая является частью веб-страницы или страницы), или загрузите и сохраните ее на локальном компьютере в качестве вложения, соответственно.inline
а такжеattachment
.
Content-Disposition: inline
Content-Disposition: attachment
В режиме вложения вы также можете указать имя файла и расширение загружаемого файла.
Content-Disposition: attachment; filename="filename.jpg"
Образец кода:
router.get('/hello.json', (ctx) => {
ctx.type = 'application/json';
ctx.set('Content-Disposition', 'attachment; filename="hello.json"');
// 上面两行代码,可以简写成 ctx.attachment('hello.json');
ctx.body = {
hello: 'world',
};
});
Затем посетите маршрут только что, и вы увидите, что файл загружен.
Атрибут загрузки HTML
Существует также способ позволить браузеру сохранить файл локально. Он добавляется HTML5 биркойdownload
Атрибуты.
<a href="/images/xxx.jpg" download="panda.jpg" >My Panda</a>
Когда пользователь нажимает на метку, загружается файл, указанный в href, иdownload
Значение атрибута соответствует имени загружаемого файла. Более гибкий способ — инкапсулировать его в метод, динамически создать ссылку, инициировать щелчок, чтобы загрузить ее напрямую и сохранить как.
<script>
function downloadAs (url, fileName) {
const link = document.createElement('a');
link.href = url;
link.download = fileName;
link.target = '_blank'
document.body.appendChild(link);
link.click();
link.remove();
}
downloadAs('http://localhost:3001/hello.json', 'world.json');
</script>
Инициируйте асинхронное получение ресурсов, а затем загрузите
В некоторых сценариях двоичное содержимое может быть возвращено только через асинхронный запрос, а затем загружено внешним интерфейсом.
С помощью атрибута загрузки в сочетании с Blob, Url.createObjectURL(), внешний интерфейс может асинхронно запрашивать ресурсы и экспортировать файлы.
const xhr = new XMLHttpRequest();
xhr.open('GET', 'http://localhost:3001/pack.zip');
xhr.responseType = 'blob';
xhr.onload = function () {
const blob = xhr.response;
const url = URL.createObjectURL(blob);
downloadAs(url, 'mypack.zip');
URL.revokeObjectURL(url);
};
xhr.send();
настраиватьxhr.responseType = 'blob'
затем, когда запрос завершается нормальноxhr.response
Получается объект Blob, URL.createObjectURL(Blob), и получается ссылка на большой двоичный объект, например:blob:http://localhost:3001/11a01a60-e10c-4515-825f-fb4a4219b33b
. Затем вы можете напрямую установить href для тега a как обычный URL-адрес.
BlobObject представляет собой неизменяемый, примитивный объект, похожий на файл данных. Объект File также расширяется на его основе и временно понимается как абстрактный файловый объект.
Передача URL.createObjectURL создает URL-адрес, который ссылается на объект Blob или File. Жизненный цикл этого URL-адреса привязан к окну, и его следует вызывать при исчерпании утечек памяти.URL.revokeObjectURL()
освобожден.
Большой двоичный объект может принимать данные собственного типа Javascript в качестве параметров, например чистые данные имитации внешнего интерфейса, и экспортировать их в виде CSV-файла.
const rows = [
["id", "firstname", "lastname"],
["1", "foo", "foo"],
["2", "bar", "baz"],
];
const data = rows.reduce(function(cur, next) {
return cur + next.join(',') + '\n';
}, '');
const blob = new Blob([data]);
const url = URL.createObjectURL(blob);
downloadAs(url, 'mock.csv');
совместимость
Совместимость атрибута загрузки невысокая, на данный момент всего 80%. можно использовать напрямуюFileSaver.jsВыполните резервную обработку.
Расширенное чтение
Подавать жалобы
Первоначальный заголовок этой статьи был «Самая сильная загрузка и загрузка файлов с помощью внешнего интерфейса во Вселенной». Когда я был на полпути к проверке информации, я обнаружил, что многие люди в Nuggets уже написали подобные статьи.
- Team Suger_Внешний интерфейс реализует загрузку файлов и загрузку методом перетаскивания
- luffyZhou_Это должно быть самое полное описание загрузок, которое вы когда-либо видели
- ...
Менталитет сломан, и пересматривать проект уже поздно, так тому и быть. (полдня потрачено впустую)
Я желаю всем счастливого китайского Нового года и преуспевающих бонусов в конце года.