anuário
introdução
Recentemente eu estava trabalhando em um site que precisa fazer o upload e download de arquivos. Parece que para algumas pessoas, é um lugar de tormento, então eu pensei que eu deveria escrever um pequeno artigo ( desde o meu último artigo foi demasiado longo, expirou há muito tempo ) , tanto para a minha própria prole, também para outras coisas.
fundo
Estou construindo uma aplicação que armazena vendas de produtos digitais. Todos os front-end com VueJS escritos com um núcleo ASP.NET backend API , para a prestação de arquivo e SPA .
Usando o código
O código é fácil de explicar, por isso vou apenas brevemente descreve a função de cada módulo, em vez da descrição detalhada de todos os conteúdos e atrapalhar o tópico.
Regista a tua API
main.ts
Importar seu api módulo
import api from './services/api'; -- this is my sites api
...
Vue.prototype.$api = api;
api-plugin.d.ts
Os api $ variáveis ligados ao Vue e atribuir Api tipo.
import { Api } from './services/api';
declare module 'vue/types/vue' {
interface Vue {
$api: Api;
}
}
export default Api;
Carregar arquivo
Em meus VueJS montagem, I dados () cria um objeto interno variável utilizada para salvar o arquivo a ser enviado para o servidor.
files: new FormData(),
Eu adicionei o usuário para responder a um método de manipulador para adicionar arquivos para fazer upload de arquivos
handleFileUpload(fileList: any) {
this.files.append('file', fileList[0], fileList[0].name);
},
Vue modelo de componente contém o elemento de entrada de arquivo
<input type="file" v-on:change="handleFileUpload($event.target.files)" />
submissão
Então, quando um usuário em sua UI ao executar operações desencadeadas upload, eu vou chamar meu API .
this.$api.uploadFile(this.files)
.then((response: <<YourResponseType>>) => {
this.hasError = false;
this.message = 'File uploaded';
}).catch((error) => {
this.hasError = true;
this.message = 'Error uploading file';
});
API métodos de serviço
No exemplo acima tern método de montagem que aparece na minha API chama esse método no serviço.
public async uploadFile(fileData: FormData): Promise<<<YourResponseType>>> {
return await axios.post('/api/to/your/upload/handler', fileData, { headers: { 'Content-Type': 'multipart/form-data' } })
.then((response: any) => {
return response.data;
})
.catch((error: any) => {
throw new Error(error);
});
}
API ASP.NET Núcleo método
O código no método de acordo com suas próprias necessidades são muito diferentes, mas a estrutura básica se parece com isso.
[HttpPost("/api/to/your/upload/handler")]
[Consumes("multipart/form-data")]
public async Task<IActionResult> UploadHandler(IFormCollection uploads)
{
if (uploads.Files.Length <= 0) { return BadRequest("No file data"); }
foreach (var f in uploads.Files)
{
var filePath = "YourGeneratedUniqueFilePath";
using (var stream = System.IO.File.Create(filePath))
{
await file.CopyToAsync(stream);
}
}
return Ok();
}
Baixar o arquivo
O início do lado do servidor, a sua API método é mostrado abaixo. Desde que eu uso Kestral uma vez que, eu escolhi usar o ControllerBase.PhysicalFile () método, mas se o controlador é mais adequado para suas necessidades, então o controlador, bem como método de controle básico que retorna ControllerBase.File () .
Desde que eu carregar e armazenar meus dados associados com uma entidade, que é exigido pelo ID valor pedido download, mas você pode usar qualquer método que se adapte às suas necessidades.
[HttpGet("[action]")]
public async Task<IActionResult> GetFile(string id)
{
var dir = "GetOrBuildYourDirectoryString";
var fileName = "GetYourFileName";
var mimeType = GetMimeType(fileName);
var path = Path.Combine(dir, fileName);
return PhysicalFile(path, mimeType, version.FileName);
}
public string GetMimeType(string fileName)
{
var provider = new FileExtensionContentTypeProvider();
string contentType;
if (!provider.TryGetContentType(fileName, out contentType))
{
contentType = "application/octet-stream";
}
return contentType;
}
Nota: FileExtensionContentTypeProvider tipos de Microsoft.AspNetCore.StaticFiles NuGet pacote
Install-Package Microsoft.AspNetCore.StaticFiles -Version 2.2.0
O cliente API de download
Para chamar isso no servidor GetFile () método, o nosso cliente API necessidades de serviço para o método de download público. Isso tornaria as coisas ficam um pouco complicado. Você pode ter de configurar o servidor para fornecer e / ou divulgação de cabeçalho de disposição. Isso é um pouco além do escopo deste artigo, porque eu quero mantê-lo simples.
Eu não preciso executar nenhuma etapa especiais para aceder a este cabeçalho, mas eu tenho que executar alguma operação para extrair os dados do cliente necessárias - principalmente o nome do arquivo. Infelizmente, este código não é particularmente bom. Se alguém tiver alguma sugestão sobre como ele melhorou, por favor me avise.
public async downloadFile(id: string): Promise<void> {
return await axios.get('/api/download/getfile?id=' + id, { responseType : 'blob' } )
.then((response: any) => {
const disposition = response.headers['content-disposition'];
let fileName = '';
if (disposition && disposition.indexOf('attachment') !== -1) {
const filenameRegex = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/;
const matches = filenameRegex.exec(disposition);
if (matches != null && matches[1]) {
fileName = matches[1].replace(/['"]/g, '');
}
}
const fileUrl = window.URL.createObjectURL(new Blob([response.data]));
const fileLink = document.createElement('a');
fileLink.href = fileUrl;
fileLink.setAttribute('download', fileName);
document.body.appendChild(fileLink);
fileLink.click();
})
.catch((error: any) => {
throw new Error(error);
});
}
Isto irá definir o cliente para baixar e abrir o arquivo de utilizador local save navegador convencional de diálogo.
Proteger arquivos enviados
Em vista do código acima é " Manual " processo de arquivos de download e upload, ele pode ser considerado, navegador HTML simples arquivo na URL não é uma situação ideal. No meu exemplo, eu arquivos enviados para serem processados no diretório download.
A fim de proteger este " download " do diretório, eu estava no StartUp.cs Configurar uma pequena quantidade de lógica será mapeado para o método de .NET Núcleo IApplicationBuilder instância. Ele irá interceptar esta URL qualquer pedido e envia uma 401 resposta.
app.Map("/downloads", subApp => {
subApp.Use(async (context, next) =>
{
context.Response.StatusCode = StatusCodes.Status401Unauthorized;
});
});
Qualquer tentativa de acessar os de downloads de arquivos de pessoa no diretório será guiado, o navegador irá receber uma resposta de erro do servidor.
Eu espero que você pode encontrar uma descrição breve de alguma utilidade neste método.