The body-parser middleware commonly used for Express can parse only content-Type as
application/json
application/x-www-form-urlencoded
application/octet-stream
text/plain
Four types of data, other types (such as multipart/form-data for uploading images), are useless.
For image uploads, there is a specialized middleware called Multer that handles data with a content-Type of multipart/form-data.
Basic usage of multer
The installation
npm install --save multer
Copy the code
Epress
var express = require('express') var multer = require('multer') var upload = multer({ dest: 'uploads/') var app = express() Avatar app.post('/profile', upload.single('avatar'), function (req, res, next) {// req. // req.body will have text field data, if present}) // Upload 12 images, Post ('/photos/upload', upload.array('photos', 12), function (req, res, Next) {// req.files array type, containing multiple files // req.body will have text field data, if any}) var cpUpload = upload.fields([{name: 'avatar', maxCount: 1 }, { name: 'gallery', maxCount: 8}]) app.post('/cool-profile', cpUpload, function (req, res, next) {// req.files is an object (String -> Array) key is a file name, Files ['avatar'][0] -> File // req.files['gallery'] -> Array // // req.body will have text field data, if it exists})Copy the code
If you need to process a form with only a text field and no file submission, you should use.none():
var express = require('express') var app = express() var multer = require('multer') var upload = multer() App.post ('/profile', upload.none(), function (req, res, next) {// req.body contains text fields})Copy the code
The file contains the following information
Key | Description | Note |
---|---|---|
fieldname |
Field name is specified by the form | |
originalname |
The name of the file on the user’s computer | |
encoding |
File coding | |
mimetype |
The MIME type of the file | |
size |
File size in bytes | |
destination |
Save the path | DiskStorage |
filename |
Stored in thedestination File name in |
DiskStorage |
path |
The full path of the uploaded file | DiskStorage |
buffer |
One that holds the entire fileBuffer |
MemoryStorage |
multer(opts)
The Multer accepts an options object, the most basic of which is the dest attribute, which tells the Multer where to save the uploaded file. If you omit the Options object, the files are kept in memory and never written to disk. Avoid memory overflow when writing data to the memory and try to write data to the disk.
To avoid naming conflicts, Multer changes the file name of the uploaded file. This renaming function can be customized to your needs.
Here are the options you can pass to Multer.
Key | Description |
---|---|
dest or storage |
Where do I store files |
fileFilter |
File filters that control which files can be accepted |
limits |
Limit uploaded data |
preservePath |
Save the full file path with the file name |
In general, for a normal web application, you just need to set the dest attribute like this:
var upload = multer({ dest: 'uploads/' })
Copy the code
If you want more control over uploading, you can use the storage option instead of Dest. Multer has DiskStorage and MemoryStorage engines. There are also more available from third parties.
.single(fieldname)
Accept a file named FieldName. The information for this file is saved in req.file.
.array(fieldname[, maxCount])
Accepts an array of files named FieldName. MaxCount can be configured to limit the maximum number of uploads. Information about these files is saved in req.files.
.fields(fields)
Accepts mixed files for the specified fields. Information about these files is saved in req.files.
Fields should be an array of objects and should have a name and optional maxCount attribute.
Example:
[
{ name: 'avatar', maxCount: 1 },
{ name: 'gallery', maxCount: 8 }
]
Copy the code
.none()
Only text fields are accepted. “LIMIT_UNEXPECTED_FILE” error occurs if any files are uploaded to this mode. This has the same effect as upload.fields([]).
.any()
Accept all uploaded files. The array of files will be saved in req.files.
Warning: Make sure you always handle user file uploads. Never use multer as global middleware, because malicious users can upload files to a route you didn’t expect, and should only be used on routes where you need to handle uploading files.
storage
Disk storage engine (DiskStorage
)
The disk storage engine allows you to control the storage of files.
var storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, '/tmp/my-uploads')
},
filename: function (req, file, cb) {
cb(null, file.fieldname + '-' + Date.now())
}
})
var upload = multer({ storage: storage })
Copy the code
There are two options available, Destination and filename. They are all functions used to determine where files are stored.
Destination is used to determine in which folder the uploaded file should be stored. You can also provide a string (e.g. ‘/ TMP /uploads’). If destination is not set, the default temporary folder of the operating system is used.
Note: If you provide destination as a function, you are responsible for creating the folder. When providing a string, multer will ensure that the folder is created by you.
Filename is used to determine the name of the file in the folder. If filename is not set, each file is set to a random filename with no extension.
Note: Multer does not add any extensions for you, and your program should return a full filename.
Each function passes the request object (REQ) and some information about the file (file) to help with your decision.
Note that the req.body may not be fully populated, depending on the order in which fields and files are sent to the server to the client.
Memory storage engine (MemoryStorage
)
The memory storage engine stores files in Buffer objects in memory without any options.
var storage = multer.memoryStorage()
var upload = multer({ storage: storage })
Copy the code
When using an in-memory storage engine, the file information will contain a buffer field that contains the entire file data.
Warning: When you use memory storage, uploading very large files, or too many small files, can cause your application to run out of memory.
limits
An object that specifies some data size limits. Multer uses busboy through this object. Detailed features can be found on Busboy’s page.
You can use the following:
Key | Description | Default |
---|---|---|
fieldNameSize |
Field Indicates the maximum length of the name | 100 bytes |
fieldSize |
The maximum length of the field value | 1MB |
fields |
Maximum number of non-file fields | infinite |
fileSize |
Maximum file length in bytes in a multipart form | infinite |
files |
In the multipart form, the maximum number of files | infinite |
parts |
In the multipart form, the maximum number of parts to transfer (fields + files) | infinite |
headerPairs |
The maximum number of key-value pairs in a multipart form | 2000 |
Limits can help protect your site from denial of service (DoS) attacks.
fileFilter
Set up a function to control what files can be uploaded and what files should be skipped. The function should look like this:
Function fileFilter (req, file, cb) {// This function should call 'cb' using Boolean to indicate whether the file should be accepted // reject the file using 'false', like this: Cb (null, false) // Accept the file and use 'true', like this: cb(null, true) // If there is a problem, you can always send an Error like this: cb(new Error('I don't have a clue! '))}Copy the code
Error handling
When an error is encountered, Multer will send the error to Express. You can use a better error display page (express standard).
If you want to catch errors from multer, you can call the middleware program yourself. If you want to catch Multer errors, you can use the MulterError class under the Multer object (err Instanceof multer.multerError).
var multer = require('multer') var upload = multer().single('avatar') app.post('/profile', function (req, res) { upload(req, res, Function (err) {if (err instanceof multer.multerError) {if (err instanceof multer.multerError) {else if (err) {err instanceof multer.multerError)})})Copy the code
The front-end code
Direct form submission
<form action="/profile" method="post" encType ="multipart/form-data"> <h2> <input type="file" name="avatar"> < form> </form>Copy the code
Form submission requires encType =”multipart/form-data” to ensure that the content-Type is multipart/form-data
JQuery asynchronous submission
<input type="file" name="avatar" id="fileUploader" SRC = "http://cdn.bootcss.com/jquery/3.1.0/jquery.min.js" > < / script > < script > function uploadFile () {var formData = new FormData(); var file = document.getElementById('fileUploader').files[0]; Formdata. append('avatar', file); $.ajax({ url : '/profile', type : 'post', data : FormData, // processData Defaults to true, will convert data to string transmission, must be set to false processData: False, // contentType default 'application/x-www-form-urlencoded; Charset = utf-8 '// Do not set multipart/form-data to false, contentType: false, success: function (res) { console.log(res); }, }) } </script>Copy the code
multipart/form-data
A common way to submit data. When we use forms to upload files, we must let
Request Headers
POST /profile HTTP/1.1
Host: localhost:3000
Connection: keep-alive
Content-Length: 20502
Pragma: no-cache
Cache-Control: no-cache
Accept: application/json, text/javascript, */*; q=0.01
Origin: http://localhost:3000
X-Requested-With: XMLHttpRequest
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryIRoGm8wWREx5foPw
Form Data
------WebKitFormBoundaryIRoGm8wWREx5foPw
Content-Disposition: form-data; name="avatar"; filename="2646377831-58e393a0c7822_articlex.png"
Content-Type: image/png
------WebKitFormBoundaryIRoGm8wWREx5foPw--
Copy the code
First, a boundary was generated to divide different fields. In order to avoid repetition with the text, the boundary was very long and complicated.
Then the content-Type indicates that the data is encoded with multipart/form-data, and what is the Content of boundary in this request.
The message body is divided into several parts with similar structure according to the number of fields. Each part starts with –boundary, followed by content description information, carriage return, and finally the specific content of the field (text or binary). If you are transferring a file, also include the filename and file type information.
The message body ends with a –boundary– identifier.
Here’s an example:
<form action="/profile" method="post" enctype="multipart/form-data"> <input type="file" name="avatar" > <input Check</input> <button type="submit" </button> </form>Copy the code
Click Submit and submit as follows
POST /profile HTTP/1.1
Host: localhost:3000
Connection: keep-alive
Content-Length: 1814270
Pragma: no-cache
Cache-Control: no-cache
Origin: http://localhost:3000
Upgrade-Insecure-Requests: 1
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryJuLO36ZzIGEt5gGs
------WebKitFormBoundaryJuLO36ZzIGEt5gGs
Content-Disposition: form-data; name="avatar"; filename="red-btn.png"
Content-Type: image/png
(imagedata)
------WebKitFormBoundaryJuLO36ZzIGEt5gGs
Content-Disposition: form-data; name="myTextField"
2
------WebKitFormBoundaryJuLO36ZzIGEt5gGs
Content-Disposition: form-data; name="myCheckBox"
on
------WebKitFormBoundaryJuLO36ZzIGEt5gGs--
Copy the code
Reference Documents:
The jQuery ajax document: api.jquery.com/jquery.ajax…
Multer documentation: github.com/expressjs/m…