Express
For example, the following code creates a Web server at port 3000
const express = require("express");
const app = express();
app.listen(3000.() = > {
console.log("start");
});
Copy the code
In my understanding express is just a function called to a set of middleware
For example, common methods for handling GET and POST requests are middleware calls
When we require express, we’re essentially importing a function
You can view the source code below as an extract of the entry file express.js
exports = module.exports = createApplication;
/**
* Create an express application.
*
* @return {Function}
* @api public* /
function createApplication() {
var app = function (req, res, next) {
app.handle(req, res, next);
};
mixin(app, EventEmitter.prototype, false);
mixin(app, proto, false);
// expose the prototype that will get set on requests
app.request = Object.create(req, {
app: { configurable: true.enumerable: true.writable: true.value: app },
});
// expose the prototype that will get set on responses
app.response = Object.create(res, {
app: { configurable: true.enumerable: true.writable: true.value: app },
});
app.init();
return app;
}
Copy the code
Express.js exports a function called createApplication, which is the function that we require to import
In this function, we initialize an app function with req/res/next and we mix a lot of properties into the app with the minin function
Specific apis can consult expressjs.com/en/4x/api.h…
The middleware
A callback function passed to Express the middleware is located between the request and the response so it can
• Execute any code
• Change the request and response objects
• End the request response period res.end
• Call the next middleware
We can use the app.use method to register the middleware globally so that all routes will match the middleware
You can also use middleware in specific routing as shown below
const middlewareA = ((req,res,next) = >{
do something...
})
app.use(middlewareA)
app.get('/', middlewareA ,(req,res,next) = >{
do something...
})
Copy the code
Managed static file
const express = require("express");
const path = require("path");
const app = express();
// Use /static to access the public folder
app.use("/static", express.static(path.join(__dirname, "public")));
app.listen(8080.() = > {
console.log("Static resource server deployed successfully");
});
Copy the code
get
The parameters of the get request are all in the URL and we can get them in the form of query and params
const express = require("express");
const app = express();
app.get("/query".(req, res, next) = > {
res.json(req.query);
});
app.get("/param/:id".(req, res, next) = > {
res.json(req.params);
});
app.listen(3000.() = > {
console.log("start");
});
Copy the code
post
The parameter of the POST request is in the body but if we print the body directly we won’t see any results
This requires the introduction of the body-Parser library
This library integrates with the different versions of Express as follows
-
3. The built-in x
-
4. X
-
4.16 Built-in functions
So we need to manually install this third-party library for versions prior to 4.x 4.16
const express = require("express");
const app = express();
// The old version is not recommended
// var bodyParser = require("body-parser");
// app.use(bodyParser.urlencoded({ extended: false }));
// app.use(bodyParser.json());
// We recommend writing after 4.16
// Extended False is parsed using Node's built-in queryString module
// True means using the third-party module QS
app.use(express.urlencoded({ extended: false }));
app.use(express.json());
app.post("/login".(req, res, next) = > {
console.log(req.body);
});
app.listen(8000.() = > {
console.log("start");
});
Copy the code
File upload
If you do this in the native way it’s going to be a lot of trouble in the background because the binary stream has not only the information about the file but also some information about the header so we can print out some of that data and look at it
const express = require("express");
const app = express();
app.post("/upload".(req, res, next) = > {
console.log(req.headers);
let data = "";
req.on("data".(buffer) = > {
data += buffer;
});
req.on("end".() = > {
console.log(data.toString());
});
});
app.listen(8080.() = > {
console.log("start~~~");
});
Copy the code
Localhost :8080/upload = localhost:8080/upload = localhost:8080/upload = localhost:8080/upload = localhost:8080/upload = localhost:8080/upload
Headers information is as follows
{
"user-agent": "PostmanRuntime / 7.13.0"."accept": "* / *"."cache-control": "no-cache"."postman-token": "e48f538d-2988-4e39-8d50-80fdede0ed02"."host": "localhost:8080"."accept-encoding": "gzip, deflate"."content-type": "multipart/form-data; boundary=--------------------------372446874075094600561084"."content-length": "376074"."connection": "keep-alive"
}
Copy the code
If you look closely, you will see that the binary stream contains the content-type in the header and the MIME type of the file. If you write the binary stream to the file using the FS module without any processing, the final file will not be parsed correctly
If you introduce the Multer module, the file upload function becomes easy
For example, we need the user to upload the avatar code as follows
const express = require("express");
const multer = require("multer");
const path = require("path");
const storage = multer.diskStorage({
destination: function (req, file, cb) {
// Node callbacks with err as first argument are error-first callbacks
// The second parameter is the destination of the file upload
cb(null."uploads");
},
filename: function (req, file, cb) {
// Again, the first parameter is the error message and the second parameter is the file name
cb(
null,
file.fieldname + "-" + Date.now() + path.extname(file.originalname) ); }});const upload = multer({ storage: storage });
const app = express();
app.post("/upload", upload.single("avatar"), (req, res, next) = > {
console.log(req.file);
});
app.listen(8080.() = > {
console.log("start~~~");
});
Copy the code
The above method demonstrates a single file upload to req.file where the file information is stored as follows
{
"fieldname": "avatar"."originalname": "CHOU16.jpg"."encoding": "7bit"."mimetype": "image/jpeg"."destination": "uploads"."filename": "avatar-1616384964609.jpg"."path": "uploads\\avatar-1616384964609.jpg"."size": 375864
}
Copy the code
If you need to support multiple file uploads, for example, you also need to upload user background images, the code can be rewritten as follows
app.post(
"/fields",
upload.fields([
{ name: "avatar".macCount: 1 },
{ name: "bg".maxCount: 2},]),(req, res, next) = > {
console.log(req.files); });/ / {
// avatar: [
/ / {
// fieldname: 'avatar',
// originalname: 'CHOU1.jpg',
// encoding: '7bit',
// mimetype: 'image/jpeg',
// destination: 'uploads',
// filename: 'CHOU1.jpg',
// path: 'uploads/CHOU1.jpg',
// size: 646567
/ /}
/ /,
// bg: [
/ / {
// fieldname: 'bg',
// originalname: 'CHOU2.jpg',
// encoding: '7bit',
// mimetype: 'image/jpeg',
// destination: 'uploads',
// filename: 'CHOU2.jpg',
// path: 'uploads/CHOU2.jpg',
// size: 398519
/ /}
/ /]
// }
Copy the code
If you want to upload multiple background images to the same field, you can use the array method. The second parameter is the maximum number of images that can be uploaded
If the maximum number is exceeded, multer will return MulterError: Unexpected field
app.post("/array", upload.array("bg".3), (req, res, next) = > {
console.log(req.files);
});
/ / /
/ / {
// fieldname: 'bg',
// originalname: 'CHOU1.jpg',
// encoding: '7bit',
// mimetype: 'image/jpeg',
// destination: 'uploads',
// filename: 'CHOU1.jpg',
// path: 'uploads/CHOU1.jpg',
// size: 646567
/ /},
/ / {
// fieldname: 'bg',
// originalname: 'CHOU2.jpg',
// encoding: '7bit',
// mimetype: 'image/jpeg',
// destination: 'uploads',
// filename: 'CHOU2.jpg',
// path: 'uploads/CHOU2.jpg',
// size: 398519
/ /}
// ]
Copy the code
router
If all request processing is handled in index.js, the index.js code will become bloated. In this case, we can use the route to break up our code
For example, there is a user module in the project to achieve the function of adding, deleting, changing and checking
We can create a new user.js file
const express = require("express");
const router = express.Router();
router.get("/add".(req, res, next) = > {
res.end("added");
});
router.post("/delete".(req, res, next) = > {
res.end("deleted");
});
router.post("/update".(req, res, next) = > {
res.end("updated");
});
router.post("/select".(req, res, next) = > {
res.end("selected");
});
module.exports = router;
Copy the code
Then import the route in index.js
const express = require("express");
const userRouter = require("./user");
const app = express();
app.use("/user", userRouter);
app.listen(3000.() = > {
console.log("start");
});
Copy the code
DEMO
The middleware in Express is all synchronous code, that is, one piece of middleware executes before the other piece of middleware executes
For example, we have the following functions to append content to message respectively in ABC middleware and output results in MIDDLEWARE A
const express = require("express");
const app = express();
const middlewareA = (req, res, next) = > {
req.message = "";
req.message += "A";
next();
res.end(req.message);
};
const middlewareB = (req, res, next) = > {
req.message += "B";
next();
};
const middlewareC = async (req, res, next) => {
req.message += "C";
next();
};
app.use(middlewareA);
app.use(middlewareB);
app.use(middlewareC);
app.listen(8000.() = > {
console.log(8000);
});
Copy the code
The next function finds the next middleware in the stack and executes, so the res.end in the middlewareA executes ABC only after all middleware has been executed
So what happens if we simulate asynchronous operations with timers in the third middleware
MiddlewareC is transformed as follows
const middlewareC = (req, res, next) = > {
setTimeout(() = > {
req.message += "C";
}, 0);
next();
};
Copy the code
By accessing port 8000 we can see that this time the final output becomes AB and so you can see that
The code in the middleware is invoked synchronously
This is a weakness of Express for asynchronous scenarios, unlike KOA
Koa
Koa supports the use of async and await functions, which means that koA can throw away the writing of callback functions in Express to address asynchronous scenarios in a more elegant way
The basic use
Unlike Express, KOA exports not a function but an object called Application
So we only need an instance of new to use it. Otherwise, it is similar to Express
const Koa = require("koa");
const app = new Koa();
app.listen(8080.() = > {
console.log("Koa");
});
Copy the code
routing
In this case, we’re going to use a third party module called KOA-Router because KOA itself is very pure and basically everything has to be done through a third party plug-in
Create a new route module Koa of user.js and combine the request and response in Express into the context object context abbreviated as CTX
const Router = require("koa-router");
const userRouter = new Router({ prefix: "/user" });
userRouter.get("/home".(ctx, next) = > {
ctx.body = "welcome~~";
});
userRouter.post("/login".(ctx, next) = > {
ctx.body = "login";
});
module.exports = userRouter;
Copy the code
Then introduce user.js into the index
const Koa = require("koa");
const userRouter = require("./router");
const app = new Koa();
app.use(userRouter.routes());
app.listen(8080.() = > {
console.log("Koa");
});
Copy the code
Handle the request
Koa needs to introduce koA-BodyParser to parse JSON and Urlencoded
const Koa = require("koa");
const Router = require("koa-router");
const bodyParser = require("koa-bodyparser");
const app = new Koa();
const router = new Router();
app.use(bodyParser());
app.use(router.routes());
/ / query
router.get("/query".(ctx, next) = > {
console.log(ctx.request.query);
});
/ / parsing params
router.get("/params/:id".(ctx, next) = > {
console.log(ctx.request.params);
});
/ / parsing urlencoded
router.post("/urlencoded".(ctx, next) = > {
console.log(ctx.request.body);
});
/ / parsing json
router.post("/json".(ctx, next) = > {
console.log(ctx.request.body);
});
app.listen(8080.() = > {
console.log("start");
});
Copy the code
Note that the koa-BodyParser middleware needs to be used first
Asynchronous processing
Going back to the Demo in Express makes it very easy to handle asynchronous operations in KOA
const Koa = require("koa");
const axios = require("axios");
const app = new Koa();
const middlewareA = async (ctx, next) => {
ctx.msg = "";
ctx.msg += "A";
await next();
ctx.body = ctx.msg;
};
const middlewareB = async (ctx, next) => {
ctx.msg += "B";
await next();
};
const middlewareC = async (ctx) => {
const res = await axios.get("https://koa.bootcss.com/");
ctx.msg += res.data;
};
app.use(middlewareA);
app.use(middlewareB);
app.use(middlewareC);
app.listen(8080.() = > {
console.log("Koa");
});
Copy the code
The onion model
The onion model is actually not a tall and fashionable concept, as we can see from the following figure, right
All the middleware is accessed twice by the request just like peeling the onion and that’s the onion model
Express contrast koa
-
Express is complete and powerful, which helps us build in a lot of useful features;
-
Koa is clean and free, it only contains the core functionality and does not restrict our use of other middleware. Even the most basic get and post are not provided to us in the app; We need to determine the request mode or other functionality by ourselves or by the route
-
Koa middleware supports async await