后端文件上传获取文件名
In this tutorial, I will be teaching on how to upload files in Angular 2+.
在本教程中,我将教授如何在Angular 2+中上传文件。
Throughout this tutorial, Angular means Angular version greater than 2.x unless stated otherwise.
在本教程中,除非另有说明,否则Angular表示Angular版本大于2.x。
In this tutorial, I will also help you all create a server script that handles the file uploads.
在本教程中,我还将帮助大家创建一个处理文件上传的服务器脚本。
I will teach two methods of file uploads using Angular.
我将教两种使用Angular上传文件的方法。
The first method entails using the ng2-file-upload
package, while the second method is handling the uploads without using any third party package.
第一种方法需要使用ng2-file-upload
软件包,而第二种方法是在不使用任何第三方软件包的情况下处理上传。
我们将建立什么 ( What We Will Build )
This is what the app will look like when we are done building.
![](https://scotch-res.cloudinary.com/image/upload/w_auto,q_auto:good,f_auto/media/17209/DgOcM8ACRN2YuxmUcC2a_ezgif.com-video-to-gif%281%29.gif)
这就是我们完成构建后应用程序的外观。
Express Generator入门 ( Getting Started With Express Generator )
To get started, we will need to install express generator, to take care of the configurations, and make our work much easier.
首先,我们将需要安装Express Generator,以照顾好配置并简化我们的工作。
So we run this command.
因此,我们运行此命令。
sudo npm install -g express-generator
Once Express generator has been installed, its time to create our application.
一旦安装了Express generator,就可以创建我们的应用程序了。
So we run the following command.
因此,我们运行以下命令。
express -e angular-file
After creating the application, we would need to move into the directory, and run npm install
创建应用程序后,我们需要进入目录,然后运行npm install
cd angular-file
npm install
At this point, if we run ng start
command, we should be able to see the default express page.
此时,如果我们运行ng start
命令,我们应该能够看到默认的express页面。
安装Multer库 ( Installing The Multer Library )
The next step would be to install Multer
. Multer is a package for handling file uploads in express js. To install Mutler, we run the following command.
下一步将是安装Multer
。 Multer是用于处理Express js中文件上传的软件包。 要安装Mutler,我们运行以下命令。
npm install multer --save
At this point, we have multer installed, we would need to use it in the route handling our upload function.
至此,我们已经安装了multer,我们需要在处理上传功能的路由中使用它。
设置上传路线 ( Setting Up The Upload Route )
Let us open up our routes\index.js
and replace it with the following:
让我们打开routes\index.js
并将其替换为以下内容:
//require express library
var express = require('express');
//require the express router
var router = express.Router();
//require multer for the file uploads
var multer = require('multer');
// set the directory for the uploads to the uploaded to
var DIR = './uploads/';
//define the type of upload multer would be doing and pass in its destination, in our case, its a single file with the name photo
var upload = multer({dest: DIR}).single('photo');
/* GET home page. */
router.get('/', function(req, res, next) {
// render the index page, and pass data to it.
res.render('index', { title: 'Express' });
});
//our file upload function.
router.post('/', function (req, res, next) {
var path = '';
upload(req, res, function (err) {
if (err) {
// An error occurred when uploading
console.log(err);
return res.status(422).send("an Error occured")
}
// No error occured.
path = req.file.path;
return res.send("Upload Completed for "+path);
});
})
module.exports = router;
In the above route file, we imported the mutler library, Created a variable DIR
, that holds the destination point, we then define an upload varaible, that holds the mutler upload function
telling it that it would be uploading a single file, with the name photo
.
在上面的路由文件中,我们导入了mutler库,创建了一个变量DIR
,该变量保存了目标点,然后定义了一个上载变量,其中包含了mutler upload function
告诉它它将上载单个文件,名称为photo
。
In our post route, we call the upload function, acting as a middleware, adding a callback, so we can know if the file was uploaded or not.
在我们的发布路线中,我们调用上载函数,充当中间件,并添加回调,这样我们就可以知道文件是否已上载。
Once the file has been uploaded, mutler provides an interface for us to get the location of the file that has been uploaded, using the req.file.path
, which we assign to a variable, and return it as the success message.
上载文件后,mutler使用为我们分配给变量的req.file.path
为我们提供一个接口,以获取上载文件的位置,并将其作为成功消息返回。
At this point, however, if we try to access the route from any client and upload files to it, it would give a cors origin blocked error
, which of cause, is right, as we are going to be calling the upload api from another domain.
但是,在这一点上,如果我们尝试从任何客户端访问该路由并将文件上传到该客户端,它将给出一个cors origin blocked error
,原因是正确的,因为我们将从另一个调用api域。
However, there's a fix for that.
但是,有一个解决方法。
创建Cors中间件 ( Creating The Cors Middleware )
Locate your app.js
file in the root folder, and lets locate the line that says app.use('/', routes)
and just before that line, lets add the following:
在根文件夹中找到您的app.js
文件,让我们找到显示app.use('/', routes)
行,并在该行之前添加以下内容:
//create a cors middleware
app.use(function(req, res, next) {
//set headers to allow cross origin request.
res.header("Access-Control-Allow-Origin", "*");
res.header('Access-Control-Allow-Methods', 'PUT, GET, POST, DELETE, OPTIONS');
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
next();
});
What we have done above, is to create a middleware, that adds the cors origin header ro the response, as well as allowed methods for that origin.
上面我们做的是创建一个中间件,在响应中添加cors原始标头,以及该原始的允许方法。
At this point, we can hit ctrl+c
on the terminal, and then run npm start
again to reload changes.
至此,我们可以在终端上按ctrl+c
,然后再次运行npm start
来重新加载更改。
Our server Script is now ready to receive and upload files to our root upload folder.
现在,我们的服务器脚本已准备就绪,可以接收文件并将其上传到我们的根上载文件夹。
Angular Cli入门 ( Getting Started With The Angular Cli )
Now it's time we move to create the angular project that does the file upload.
现在是时候该创建创建文件上传的角度项目了。
let's move into the public folder, and we would use the angular-cli to create a new angular project
让我们进入公用文件夹,然后使用angular-cli创建一个新的角度项目
So we run the below command to install the angular-cli which is a Command Line Interface for developing Angular apps.
因此,我们运行以下命令安装angular-cli,这是用于开发Angular应用程序的命令行界面。
So in our terminal, we run the following command to install it and create a new project.
因此,在我们的终端中,我们运行以下命令来安装它并创建一个新项目。
//install the angular-clinpm install -g angular-cli
//change directory to the public folder of our working directory
cd public
//create a new angular project called testupload.
ng new testupload
//change directory to the test upload folder
cd testupload
//serve the angular application
ng serve
At this point, we see that npm packages are being installed, and as such, we wait till they are done.
至此,我们看到正在安装npm软件包,因此,我们等待它们完成。
Once they have been installed, we can run the ng serve
to serve our application for us to see.
安装它们后,我们可以运行ng serve
服务我们的应用程序,以供我们查看。
Extra Reading on Angular Cli Use the Angular CLI For Faster Angular 2 Projects
在Angular Cli上进行更多阅读使用Angular CLI进行更快的Angular 2项目
Now it's time to create the actual file upload.
现在是时候创建实际的文件上传了。
使用Ng2-File-Upload软件包 ( Using The Ng2-File-Upload Package )
Method 1. Using the ng2-file-upload package.
方法1.使用ng2-file-upload软件包 。
Now after we have served the application, we would see a screen like this when we navigate to localhost:4200
.
![](https://scotch-res.cloudinary.com/image/upload/w_auto,q_auto:good,f_auto/media/17209/Cd0Am45cTK2434KT6Q1y_Screenshot%20from%202017-01-15%2015-22-53.png)
现在,在为应用程序提供服务之后,当我们导航到localhost:4200
时,将看到一个类似的屏幕。
//install thefile upload plugin and save to composer.json file.
npm i ng2-file-upload --save
This installs the module into our node-modules folder, and as well saves it into our JSON file. Now lets head over to the file in src/app/app.component.ts
这会将模块安装到我们的node-modules文件夹中,并将其保存到我们的JSON文件中。 现在让我们转到src/app/app.component.ts
的文件
We would replace the contents of the file with this one below.
我们将在下面用这个替换文件的内容。
//import component and the oninit method from angular core
import { Component, OnInit } from '@angular/core';
//import the file uploader plugin
import { FileUploader } from 'ng2-file-upload/ng2-file-upload';
//define the constant url we would be uploading to.
const URL = 'http://localhost:8000/api/upload';
//create the component properties
@Component({
//define the element to be selected from the html structure.
selector: 'app-root',
//location of our template rather than writing in-line templates.
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
//declare a property called fileuploader and assign it to an instance of a new fileUploader.
//pass in the Url to be uploaded to, and pass the itemAlais, which would be the name of the //file input when sending the post request.
public uploader:FileUploader = new FileUploader({url: URL, itemAlias: 'photo'});
//This is the default title property created by the angular cli. Its responsible for the app works
title = 'app works!';
ngOnInit() {
//override the onAfterAddingfile property of the uploader so it doesn't authenticate with //credentials.
this.uploader.onAfterAddingFile = (file)=> { file.withCredentials = false; };
//overide the onCompleteItem property of the uploader so we are
//able to deal with the server response.
this.uploader.onCompleteItem = (item:any, response:any, status:any, headers:any) => {
console.log("ImageUpload:uploaded:", item, status, response);
};
}
}
Here, we import component, alongside the OnInit class, so we can implement the ngOnInit function, which serve like a type of constructor for our component.
在这里,我们将组件与OnInit类一起导入,因此我们可以实现ngOnInit函数,该函数就像我们组件的构造函数一样。
Then we import the file uploader class. We then define a constant that holds the url we are uploading to.
然后,我们导入文件上传器类。 然后,我们定义一个常量,用于保存要上传到的网址。
In our Appcomponent class, we define a public property called uploader, and assign it to an instance of the file uploader, passing along our URL
and an extra itemAlais
property which we would call the File Input.
在我们的Appcomponent类中,我们定义了一个称为上载器的公共属性,并将其分配给文件上载器的实例,同时传递了URL
和一个额外的itemAlais
属性,我们将其称为文件输入。
The itemAlias
property refers to the name we would like to call out file input.
itemAlias
属性是指我们要调用文件输入的名称。
覆盖onAfterAddingFile
函数 (Overiding The onAfterAddingFile
Function)
We then call the ngOnit function, where we override two of the uploaders function. The first function we override is the onAfterAddingFile
function which is triggered after a file has been chosen, and we set the credentials to the file to be false. i.e we are not authenticating with credentials.
然后,我们调用ngOnit函数,在这里我们覆盖了两个uploaders函数。 我们重写的第一个函数是onAfterAddingFile
函数,该函数在选择文件后触发,并且我们将文件的凭据设置为false。 即我们不使用凭据进行身份验证。
The next function we override is the onCompleteItem
function. The reason we override this is so we can get the response from the server.
我们重写的下一个函数是onCompleteItem
函数。 覆盖此原因的原因是我们可以从服务器获取响应。
In our case, we just console log the status, response and the item.
在我们的情况下,我们只需控制台记录状态,响应和项目。
Now we move into our html file and replace it with the following content, so we can add the input type.
现在,我们进入html文件,并将其替换为以下内容,以便我们可以添加输入类型。
<h1>
<!-- here we echo the title from the component -->
{{title}}
</h1>
<!-- File input for the file-upload plugin, with special ng2-file-upload directive called ng2FileSelect -->
<input type="file" name="photo" ng2FileSelect [uploader]="uploader" />
<!-- button to trigger the file upload when submitted -->
<button type="button" class="btn btn-success btn-s"
(click)="uploader.uploadAll()"
[disabled]="!uploader.getNotUploadedItems().length">
Upload with ng-2 file uploader
</button>
So we create an input of type file and we attach the ng2FileSelect
directive to it, which makes it possible to bind the uploader attribute which it provide to our own uploader.
因此,我们创建了类型为file的输入,并将ng2FileSelect
指令附加到该输入,从而可以将其提供的uploader属性绑定到我们自己的上载器。
Then we create a button that is disabled if there is no item in the upload queue and has a click function to upload all files in the queue.
然后,我们创建一个按钮,如果上传队列中没有项目,该按钮将被禁用,并具有单击功能以上传队列中的所有文件。
However, if we save our file at this time and run it, we would run into errors.
但是,如果我们此时保存文件并运行它,则会遇到错误。
包括Ng2FileSelect
指令 (Including The Ng2FileSelect
Directive)
We would have to add a declaration to our app.module.ts
, so we can use the ng2FileSelect
directive.
我们必须在app.module.ts
添加一个声明,以便可以使用ng2FileSelect
指令。
So we add this line to the top of our app.module.ts
因此,我们将此行添加到app.module.ts
的顶部
//import the ng2-file-upload directive so we can add it to our declarations.
import { FileSelectDirective } from 'ng2-file-upload';
And we also add the FileSelectDirective
to our declarations
我们还将FileSelectDirective
添加到声明中
declarations: [
AppComponent,
FileSelectDirective
],
So our app.module.ts
should look this way.
因此,我们的app.module.ts
应该看起来像这样。
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { HttpModule } from '@angular/http';
import { FileSelectDirective } from 'ng2-file-upload';
import { AppComponent } from './app.component';
@NgModule({
declarations: [
AppComponent,
FileSelectDirective
],
imports: [
BrowserModule,
FormsModule,
HttpModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
Now if we launch our application and upload, we should see that our file is sent to the server.
现在,如果启动应用程序并上载,我们应该看到文件已发送到服务器。
So on the Root folder, if we go to uploads
folder, we should see that our images are being uploaded. Viola we just uploaded files using angular.
因此,在“根”文件夹上,如果转到“ uploads
文件夹,则应看到正在上传图像。 Viola我们只是使用angular上传文件。
使用基础表格数据 ( Using The Underlying Form Data )
However, there is a second method if we do not want to use the above plugin which requires using the underlying form-data to create the form data.
但是,如果我们不想使用上述插件,则有第二种方法,该方法需要使用基础表单数据来创建表单数据。
Let us create an extra file input and button in our app.component.html
,
让我们在app.component.html
创建一个额外的文件输入和按钮,
So our html structure looks this way.
因此,我们的html结构看起来就是这样。
<h1>
<!-- here we echo the title from the component -->
{{title}}
</h1>
<!-- File input for the file-upload plugin, with special ng2-file-upload directive called ng2FileSelect -->
<input type="file" name="photo" ng2FileSelect [uploader]="uploader" />
<!-- button to trigger the file upload when submitted -->
<button type="button" class="btn btn-success btn-s"
(click)="uploader.uploadAll()"
[disabled]="!uploader.getNotUploadedItems().length">
Upload with ng-2 file uploader
</button>
<!-- File input for upload without using the plugin. -->
<input id="photo" type="file" />
<!-- button to trigger the file upload when submitted -->
<button type="button" class="btn btn-success btn-s" (click)="upload()">
Upload with method 2
</button>
Note that i have added another file input with an id of photo, and another button which has a click event to upload.
请注意,我添加了另一个带有照片ID的文件输入,以及另一个具有点击事件要上传的按钮。
Now let's create the upload function that handles the file upload.
现在,让我们创建用于处理文件上传的上传功能。
Copy and replace your app component.ts
with this.
复制并替换您的app component.ts
。
//import component, ElementRef, input and the oninit method from angular core
import { Component, OnInit, ElementRef, Input } from '@angular/core';
//import the file-upload plugin
import { FileUploader } from 'ng2-file-upload/ng2-file-upload';
//import the native angular http and respone libraries
import { Http, Response } from '@angular/http';
//import the do function to be used with the http library.
import "rxjs/add/operator/do";
//import the map function to be used with the http library
import "rxjs/add/operator/map";
const URL = 'http://localhost:8000/api/upload';
//create the component properties
@Component({
//define the element to be selected from the html structure.
selector: 'app-root',
//location of our template rather than writing inline templates.
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
//declare a property called fileuploader and assign it to an instance of a new fileUploader.
//pass in the Url to be uploaded to, and pass the itemAlais, which would be the name of the //file input when sending the post request.
public uploader:FileUploader = new FileUploader({url: URL, itemAlias: 'photo'});
//This is the default title property created by the angular cli. Its responsible for the app works
title = 'app works!';
ngOnInit() {
//override the onAfterAddingfile property of the uploader so it doesn't authenticate with //credentials.
this.uploader.onAfterAddingFile = (file)=> { file.withCredentials = false; };
//overide the onCompleteItem property of the uploader so we are
//able to deal with the server response.
this.uploader.onCompleteItem = (item:any, response:any, status:any, headers:any) => {
console.log("ImageUpload:uploaded:", item, status, response);
};
}
//declare a constroctur, so we can pass in some properties to the class, which can be //accessed using the this variable
constructor(private http: Http, private el: ElementRef) {
}
//the function which handles the file upload without using a plugin.
upload() {
//locate the file element meant for the file upload.
let inputEl: HTMLInputElement = this.el.nativeElement.querySelector('#photo');
//get the total amount of files attached to the file input.
let fileCount: number = inputEl.files.length;
//create a new fromdata instance
let formData = new FormData();
//check if the filecount is greater than zero, to be sure a file was selected.
if (fileCount > 0) { // a file was selected
//append the key name 'photo' with the first file in the element
formData.append('photo', inputEl.files.item(0));
//call the angular http method
this.http
//post the form data to the url defined above and map the response. Then subscribe //to initiate the post. if you don't subscribe, angular wont post.
.post(URL, formData).map((res:Response) => res.json()).subscribe(
//map the success function and alert the response
(success) => {
alert(success._body);
},
(error) => alert(error))
}
}
}
What has changed?
有什么变化?
In this updated version, i have imported element ref and input from angular core.
在此更新版本中,我从角铁芯中导入了元素ref和输入。
I also imported the HTTP and response from the angular HTTP library.
我还从角度HTTP库导入了HTTP和响应。
I also went ahead to import the map and do RX's functions to be used with our HTTP class.
我还继续导入地图并执行RX的功能以与我们的HTTP类一起使用。
In the app component class, two things were added. 1.) A constructor 2.) The upload function.
在应用程序组件类中,添加了两件事。 1.)构造函数2.)上传功能。
In the constructor, we pass in our HTTP and element ref instances, so they can be accessed by this.http and this.el.
在构造函数中,我们传入HTTP和element ref实例,因此this.http和this.el可以访问它们。
The upload function here is where the work lies.
此处的上传功能就是工作所在。
We declare inputel
, which is of type htmlinputelement
, and we set it to the instance of the file input we created with an id of photo using the nativelement.queryselector
of the el
.
我们声明inputel
,这类型的htmlinputelement
,我们将它设置为我们使用了一个照片的ID创建的文件输入实例nativelement.queryselector
的中el
。
We then declare a variable filecount of type number and set it to the length of the files in the inputelement
.
然后,我们声明一个类型为number的变量filecount,并将其设置为inputelement
文件的长度。
We then use an if statement to be sure that a file was selected.
然后,我们使用if语句来确保已选择文件。
We then loop through the file and we append the first element of the file as the value of the key 'photo' which our server expects and then append to our formdata.
然后,我们遍历文件,并将文件的第一个元素附加为服务器期望的键“照片”的值,然后附加至表单数据。
We then call our http library to post to our previously defined url, sending the formData as params.
然后,我们调用http库以发布到我们先前定义的url,将formData作为参数发送。
At this point, if we try out our app and check the uploads folder, we should also see that the files are being uploaded.
在这一点上,如果我们尝试使用我们的应用程序并检查uploads文件夹,则还应该看到文件正在上传。
结论 ( Conclusion )
If you completed the above tutorial successfully, you have learned how to upload a file in Angular.
如果您成功完成了以上教程,您将学习如何在Angular中上传文件。
We have seen two different methods of uploading files. For those who do not like using thirld party libraries, we have used the underlying form data, and for those who do not mind to use plugins, we have used the ng2-file-upload plugin by valor.
我们已经看到了两种不同的上传文件的方法。 对于那些不喜欢使用第三方库的人,我们使用了基础表单数据;对于那些不介意使用插件的人,我们使用了valor的ng2-file-upload插件。
翻译自: https://scotch.io/tutorials/angular-file-uploads-with-an-express-backend
后端文件上传获取文件名