current position:Home>New generation node JS web development framework koa zero foundation entry learning notes

New generation node JS web development framework koa zero foundation entry learning notes

2022-05-15 02:06:25thankseveryday

Koa

new generation node.js web Development framework .

Set up server

node initialization package.json

npm init -y

Parameters :
-y All use default option settings , No more step-by-step confirmation .

{
    
  "name": "RyeKoa",
  "version": "1.0.0",
  "description": "Koa  Zero basic learning notes ",
  "main": "app.js",
  "scripts": {
    
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": " Watch · At ease ",
  "license": "ISC"
}

install Koa modular

cnpm install koa --save Abbreviation npm i koa -S

Parameters :
--save Will be in package.json Add the version information of the installation package

// package.json
{
    
  "name": "RyeKoa",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    
    "koa": "^2.13.1"
  }
}

Create application entry file app.js

The simplest way to achieve

// app.js
const Koa = require('koa')

const app = new Koa()

app.use(async (ctx, next) => {
    
    ctx.response.body = 'Hello Koa!'
})

app.listen(3000)

This is the simplest implementation .

Koa An application is one that contains a set of middleware Object of function , It's organized and executed in a stack like way .
app.use() Function is used to register middleware .
ctx yes Koa Context
next Middleware is a must , call next() The middleware is used to execute the next , It's useless here , Because ctx.response.body By default next()

The middleware used in the above code can also be abbreviated as the following form :

app.use(async ctx => {
    
	//  This is a  Response  Alias 
    ctx.body = 'Hello Koa!'
})

Context

Koa Context take node Of request and response Objects are encapsulated in a single object , For writing Web Applications and API Provides many useful methods . These operations are in HTTP Frequently used in server development , They are added to this level rather than higher-level frameworks , This will force the middleware to re implement this common functionality .

Every Each request will create a Context, And it is referenced as a receiver in the middleware , perhaps ctx identifier , As shown in the following code snippet :

app.use(async ctx => {
    
  ctx; //  This is a  Context
  ctx.request; //  This is a  koa Request
  ctx.response; //  This is a  koa Response
});

For convenience, many context accessors and methods delegate directly to their ctx.request or ctx.response , Otherwise they are the same . for example ctx.bodyctx.type and ctx.length Entrusted to response object ,ctx.path and ctx.method Entrusted to request.

Request Alias

The following accessors and Request Alias equivalent :

  • ctx.header
  • ctx.headers
  • ctx.method
  • ctx.method=
  • ctx.url
  • ctx.url=
  • ctx.originalUrl
  • ctx.origin
  • ctx.href
  • ctx.path
  • ctx.path=
  • ctx.query
  • ctx.query=
  • ctx.querystring
  • ctx.querystring=
  • ctx.host
  • ctx.hostname
  • ctx.fresh
  • ctx.stale
  • ctx.socket
  • ctx.protocol
  • ctx.secure
  • ctx.ip
  • ctx.ips
  • ctx.subdomains
  • ctx.is()
  • ctx.accepts()
  • ctx.acceptsEncodings()
  • ctx.acceptsCharsets()
  • ctx.acceptsLanguages()
  • ctx.get()

Response Alias

The following accessors and Response Alias equivalent :

  • ctx.body
  • ctx.body=
  • ctx.status
  • ctx.status=
  • ctx.message
  • ctx.message=
  • ctx.length=
  • ctx.length
  • ctx.type=
  • ctx.type
  • ctx.headerSent
  • ctx.redirect()
  • ctx.attachment()
  • ctx.set()
  • ctx.append()
  • ctx.remove()
  • ctx.lastModified=
  • ctx.etag=

Start the server

node app

such , Use node Command to start the server , And access the local address port 3000

Browser access address :
http://127.0.0.1:3000/
or http://localhost:3000/

here , The browser responds :
 Insert picture description here

Automatic server redeployment

Node.js Development AIDS nodemon

After modifying the code , Every time you need to stop and restart Koa application , The changes made will take effect .
Used nodemon after , It monitors all files in the project , Once the document is found to have changed , Will automatically restart the application .

install nodemon
npm i nodemon -g
Parameters
i namely install
-g Global installation ( Generally, the tools used in the command line are used to perform global installation )

Start the application :
nodemon app

such , When you modify the code :

...
app.listen(3000, () => {
    
    console.log(" The server has started ,http://localhost:3000");
})
...

On the console you will see nodemon Automatically restart the server for you :

$ nodemon app
[nodemon] 2.0.7
[nodemon] to restart at any time, enter `rs`
[nodemon] watching path(s): *.*
[nodemon] watching extensions: js,mjs,json
[nodemon] starting `node app.js`
[nodemon] restarting due to changes...
[nodemon] starting `node app.js`
 The server has started ,http://localhost:3000

middleware

Koa An application is one that contains a set of middleware Object of function , It's organized and executed in a stack like way .
Use app.use() Function is used to register middleware .
ctx It's context
next Middleware is a must , call next() The middleware is used to execute the next , without , The program will hang here .

const Koa = require('koa')
const app = new Koa()

app.use(async (ctx, next) => {
    
    ctx.name = 'Koa'
    next()
})
app.use(async ctx => {
    
    ctx.body = `Hello, ${
      ctx.name}!`
})

app.listen(3000, () => {
    
    console.log(" The server has started ,http://localhost:3000");
})

Onion model

Koa new generation node.js web Development framework . Its biggest characteristic is the unique middleware process control , It's a typical onion model .

The following two figures clearly show how a request generates a response through the middleware , It is very convenient to develop and use middleware in this mode .
 Insert picture description here

 Insert picture description here

const Koa = require('koa')

const app = new Koa()

app.use(async (ctx, next) => {
    
    console.log(' middleware 1: Start ');
    ctx.name = 'Koa'
    await next()
    console.log(' middleware 1: end ');

})

app.use(async ctx => {
    
    console.log(' middleware 2: Start ');
    ctx.body = `Hello, ${
      ctx.name}!`
    console.log(' middleware 2: end ');
})

app.listen(3000, () => {
    
    console.log(" The server has started ,http://localhost:3000");
})

The console will output :
 Insert picture description here
What about? , Is there a little feeling . When the program runs to await next() The current program will be suspended when , Go to the next middleware , After processing, we will go back to continue processing .

Koa The focus of middleware implementation

  • Context ctx Save and transfer of
  • Sequence management of middleware
  • next Use ( Be careful next() The front one await

Custom middleware

Customizing a middleware is not difficult at all .
First step : Define a method

function MidTest(ctx) {
    
    global.console.log(' Implemented custom middleware ...')
}

Second parts : Export this method

  1. Expose a function
  2. This function returns a parameter of ctx And next Of Callback function .
  3. Execute the method we want to complete in the callback function
module.exports = function () {
    
    return async function (ctx, next) {
    
        MidTest(ctx);
        // todo
        await next(); // Operation completed , Leave it to the next middleware 
        // todo
    }
}

Complete middleware definition :

// ./middleware/mid-test.js
function MidTest(ctx) {
    
    global.console.log(' Implemented custom middleware ...')
}
module.exports = function () {
    
    return async function (ctx, next) {
    
        MidTest(ctx);
        await next(); // Operation completed , Leave it to the next middleware 
    }
}

Use custom middleware :
First step : Introduce middleware

const
    MidTest = require('./middleware/mid-test')

Second parts : Register middleware

app.use(MidTest())

Running the application , You will see the execution result of the custom middleware :
 Insert picture description here

Koa route

Install routing Middleware koa-router

cnpm i koa-router -S

Use koa-router

Import routing module :

const Router = require('koa-router')

Instantiate route ( Support for passing parameters ):

const router = new Router()

Configure the routing :

router.get('/', async (ctx, next) => {
    
    ctx.body = 'Hello, Koa Router!'
})

Register routing middleware :
Routing instance router, Respectively called router.routes() and router.allowedMethods() Get two middleware . And then use app.use() Register these two middleware .

  • call router.routes() To assemble a matched route , Return a merged middleware
  • call router.allowedMethods() Get a middleware , When a non-conforming request is sent , Returns the 405 Method Not Allowed or 501 Not Implemented
app.use(router.routes())
app.use(router.allowedMethods({
    
    // throw: true, //  Throw an error , Instead of setting the response header status 
    // notImplemented: () => ' The function required by the current request is not supported ',
    // methodNotAllowed: () => ' Unsupported request mode '
}))

Complete sample code :

// app.js
const
    Koa = require('koa'),
    Router = require('koa-router')

const
    app = new Koa(),
    router = new Router()

router.get('/', async (ctx, next) => {
    
    ctx.body = 'Hello, Koa Router!'
})

app.use(router.routes())

app.listen(3000, () => {
    
    console.log(" The server has started ,http://localhost:3000");
})

Processing requests

koa-router Provides .get、.post、.put and .del Method to handle various requests , But in business , Most of us will only come into contact with POST and GET, Therefore, the next step is to explain only these two request types .

get: Used to receive GET request

router.get('/', async (ctx, next) => {
    
    ctx.body = 'Hello, Koa Router!'
})

post: Used to receive POST request

router.post('/signin', async (ctx, next) => {
    
    ctx.body = 'Hello, POST!'
})

all: Used to receive GET And POST request

router.all('/', async (ctx, next) => {
    
    ctx.body = 'Hello, POST!'
})

Request parameters

Sometimes you need to start from the requested URL Get specific parameters on , There are two main categories : params and query . The two parameters are obtained as follows :

params Parameters :
router.get('/:catalog/:title', async (ctx, next) => {
    
    ctx.body = `Hello, GET!  Page parameters  catalog:${
      ctx.params.catalog} title:${
      ctx.params.title}`
})

 Insert picture description here
 Insert picture description here

query Parameters
router.get('/user', async (ctx, next) => {
    
    console.log(ctx.query)
    ctx.body = `Hello, GET!  Page parameters  Name:${
      ctx.query.name} Age:${
      ctx.query.age}`
})

 Insert picture description here

 Insert picture description here

post Parameters

Route nesting

Route prefix

Route separation

Using static files

Set static Directory :public, And create files hello.html
 Insert picture description here

install : koa-static modular

Direct access is not accessible , Similarly, here we need to use middleware koa-static modular
install koa-static modular
npm i koa-static -S

Use : Import 、 To configure 、 register

// app.js
...
const KoaStatic = require('koa-static')
app.use(KoaStatic(__dirname + '/public'))
...

Access static resources :
 Insert picture description here

template engine

install :koa-views

cnpm i koa-views -S
cnpm i ejs -S

Write templates

Created in the root directory views Folder , stay views Create tpl_fruit.ejs file . The code is as follows :

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>

    <h1>
        <%=title %>
    </h1>
    <ul>
        <% fruits.forEach((fruit)=>{%>
            <li>
                <%=fruit %>
            </li>
            <%})%>
    </ul>

</body>

</html>

Use templates : Import 、 To configure 、 register

// app.js
...
const
    path = require('path'),
    views = require('koa-views')

//  Register template engine 
app.use(views(path.join(__dirname, 'views'), {
    
    map: {
    
        ejs: 'ejs'
    }
}))

/** *  Configure the routing  *  Use the template engine to output  */
router.get('/favourite', async (ctx, next) => {
    
    await ctx.render('tpl_fruit.ejs', {
    
        title: 'Hello, My favorite fruit :',
        fruits: ['Apple', 'Watermelon', 'Strawberry']
    })
})
...

visit :http://localhost:3000/favourite
 Insert picture description here

Interesting template suffix

//  Register template engine 
app.use(views(path.join(__dirname, 'views'), {
    
    map: {
    
        love: 'ejs'
    }
}))

/** *  Configure the routing  *  Use the template engine to output  */
router.get('/favourite', async (ctx, next) => {
    
    await ctx.render('tpl_fruit.love', {
    
        title: 'Hello, My favorite fruit :',
        fruits: ['Apple', 'Watermelon', 'Strawberry']
    })
})

such , When you customize the template , have access to .love Suffix file :
 Insert picture description here
We can also use multiple template engines at the same time :

//  Register template engine 
app.use(views(path.join(__dirname, 'views'), {
    
    map: {
    
        love: 'ejs',
        html: 'underscore'
    }
}))

If we only use one template engine ( Usually only one ), When registering the template engine , We can put it another way :

//  Register template engine 
app.use(views(path.join(__dirname, 'views'), {
    
    extension: 'ejs'
}))

The advantage of this is , When we reconfigure the route, we don't need to specify the suffix of the template :

/** *  Configure the routing  *  Use the template engine to output  */
router.get('/favourite', async (ctx, next) => {
    
    await ctx.render('tpl_fruit', {
    
        title: 'Hello, My favorite fruit :',
        fruits: ['Apple', 'Watermelon', 'Strawberry']
    })
})

thorough koa-views

The above code passes app.use(views(path, args)) Register view middleware , This will return a parameter of ctx And next Of Callback function .

Xiaobai understands : Middleware is a function with special agreement , This function has a context ctx and next Parameters .

//  middleware 
`async (ctx, next) => { ctx.name = 'Koa' next() }`

We can go straight to app.use() Register the middleware directly in :

//  Register middleware 
app.use(async (ctx, next) => {
    
    ctx.name = 'Koa'
    next()
})

Or define a function whose return value is middleware , Then register the function .

app.use(views(path, args))

So I understand views(path, args) , Let's continue to watch :

The Callback function Give context objects ctx Add name is render Function of , Used to render the view .

The following is a koa-views Source code :

function viewsMiddleware (path, {
    
  engineSource = consolidate,
  extension = 'html',
  options = {
    },
  map
} = {
    }) {
    
  return function views (ctx, next) {
    
    if (ctx.render) return next()

    ctx.render = function (relPath, locals = {
     }) {
    
      return getPaths(path, relPath, extension)
        .then((paths) => {
    
          // do something ...
        })
    }

    return next()
  }
}

Source code , Please note that :ctx.render = function (relPath, locals = {}) {} , This statement is for context ctx Added render Method , So that we can router.get() Use in ctx.render('tpl', {title: ' Using a template engine '}) Render the page .

template engine koa-art-template

art-template Chinese document
Code example :

// package.json
{
    
  "name": "RyeKoa",
  "version": "1.0.0",
  "description": " Learning resources ",
  "main": "app.js",
  "scripts": {
    
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "Rye",
  "license": "ISC",
  "dependencies": {
    
    "art-template": "^4.13.2",
    "koa": "^2.13.1",
    "koa-art-template": "^1.1.1",
    "koa-router": "^10.0.0",
    "koa-static": "^5.0.0",
    "koa-views": "^7.0.1"
  }
}
// app.js
const
    Koa = require('koa'),
    Router = require('koa-router'),
    KoaStatic = require('koa-static'),
    views = require('koa-views'),
    path = require('path'),
    render = require('koa-art-template')

const
    app = new Koa(),
    router = new Router()

/** *  Access to static resources starts from the root directory ,  instead of  public *  for example :http://localhost:3000/hello.html */
app.use(KoaStatic(path.join(__dirname, 'public')))

/** *  Configure template engine  *  stay  Koa  example  app  Registered on  *  And for the context  ctx  add to  render  Method  */
render(app, {
    
    root: path.join(__dirname, 'views'),
    extname: '.html'
})

//  Configure the routing 
router.get('/', async ctx => {
    
    ctx.render('user', {
    
        name: 'dy',
        age: '2'
    })
})

//  Merge configured routes , And register the routing middleware , And the way of request allowed 
app.use(router.routes()).use(router.allowedMethods({
    
    // throw: true, //  Throw an error , Instead of setting the response header status 
    // notImplemented: () => ' The function required by the current request is not supported ',
    // methodNotAllowed: () => ' Unsupported request mode '
}))

app.listen(3000, () => {
    
    console.log(' The server has started ,http://localhost:3000');
})
<!-- ./views/user.html -->
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title> User information </title>
</head>

<body>
    <h1> User information page </h1>
    <p> full name :{
   {name}}</p>
    <p> Age :{
   {age}}</p>
</body>

</html>

Easy to use “ Template inheritance ” and “ Sub template ”

We usually have requirements for master pages , Will be universal js、css And fixed head、footer And other parts into the master page , The master page is inherited by other pages with the above common features , This is convenient for unified management and modification .

Bootstrap It is one of the most popular front-end frameworks in the world , For convenience 、 Responsive build 、 Mobile device priority website .
Our sample directory is as follows :
 Insert picture description here

In the static resource folder public Put what we need to introduce into bootstrap Resource file , This requires you to install and To configure koa-static modular .

<!-- __layout.html -->
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>{
   {block 'title'}} Learning resources {
   {/block}}- SanHaoSheng </title>
    <link rel="stylesheet" href="/bootstrap/css/bootstrap.min.css">
    {
   {block 'head'}}{
   {/block}}
</head>

<body>
    <nav class="navbar navbar-expand-md navbar-dark fixed-top bg-dark">
        <a class="navbar-brand text-info" href="#"> Primary school Bus</a>
        <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarsExampleDefault" aria-controls="navbarsExampleDefault" aria-expanded="false" aria-label="Toggle navigation">
            <span class="navbar-toggler-icon"></span>
        </button>

        <div class="collapse navbar-collapse" id="navbarsExampleDefault">
            <ul class="navbar-nav mr-auto">
                <li class="nav-item active">
                    <a class="nav-link" href="#"> home page  <span class="sr-only">(current)</span></a>
                </li>
                <li class="nav-item">
                    <a class="nav-link" href="#"> Resource link </a>
                </li>
                <li class="nav-item">
                    <a class="nav-link disabled" href="#" tabindex="-1" aria-disabled="true"> download </a>
                </li>
                <li class="nav-item dropdown">
                    <a class="nav-link dropdown-toggle" href="#" id="dropdown01" data-toggle="dropdown" aria-expanded="false"> subject </a>
                    <div class="dropdown-menu" aria-labelledby="dropdown01">
                        <a class="dropdown-item" href="#"> English </a>
                        <a class="dropdown-item" href="#"> mathematics </a>
                        <a class="dropdown-item" href="#"> Chinese language and literature </a>
                        <a class="dropdown-item" href="#"> science </a>
                    </div>
                </li>
            </ul>

            <a class="btn btn-info" href="#"> Resource link </a>
        </div>
    </nav>

    <header>{
   {block 'header'}}{
   {/block}}</header>
    <main>
        {
   {block 'content'}} The page content {
   {/block}}
    </main>
    <footer class="container">
        <p>@ SanHaoSheng  {
   {block 'footer'}}{
   {/block}}</p>
    </footer>

    <script src="/jquery.slim.min.js"></script>
    <script src="/bootstrap/js/bootstrap.bundle.min.js"></script>
</body>

</html>

Sub template :

<!--links.html-->
<a href="#"> My blog </a> | <a href="#"> Online cloud learning </a> | <a href="#">AI  Learning Assistant </a>

home page :
{ {extend './__layout.html'}} Inherit master page
{ {include '__links.html'}} Import sub template
{ {block 'title'}}{ {title}}{ {/block}} Put custom content

<!--index.html-->
{
   {extend './__layout.html'}}

{
   {block 'title'}}{
   {title}}{
   {/block}}

{
   {block 'head'}}
<style> .bd-placeholder-img {
       font-size: 1.125rem; text-anchor: middle; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; } @media (min-width: 768px) {
       .bd-placeholder-img-lg {
       font-size: 3.5rem; } } /* Move down content because we have a fixed navbar that is 3.5rem tall */ body {
       padding-top: 3.5rem; } </style>
{
   {/block}}

{
   {block 'content'}}
<div class="jumbotron">
    <div class="container">
        <h1 class="display-3">Hello,  SanHaoSheng !</h1>
        <p> Rich learning resources , Help to become three good students ......</p>
        <p><a class="btn btn-primary btn-lg" href="#" role="button">Learn more &raquo;</a></p>
    </div>
</div>

<div class="container">
    <!-- Example row of columns -->
    <div class="row">
        <div class="col-md-4">
            <h2> Chinese language and literature </h2>
            <p> Love Chinese </p>
            <p><a class="btn btn-secondary" href="#" role="button"> Begin to learn  &raquo;</a></p>
        </div>
        <div class="col-md-4">
            <h2> mathematics </h2>
            <p> Love math </p>
            <p><a class="btn btn-secondary" href="#" role="button"> Begin to learn  &raquo;</a></p>
        </div>
        <div class="col-md-4">
            <h2> English </h2>
            <p> Love English </p>
            <p><a class="btn btn-secondary" href="#" role="button"> Begin to learn  &raquo;</a></p>
        </div>
    </div>

    <hr>

</div> <!-- /container -->
{
   {/block}}

{
   {block 'footer'}}
{
   {include '__links.html'}}
{
   {/block}}

The final effect :
 Insert picture description here

Koa Cross domain setup

Write cross domain settings using middleware :

app.use((ctx, next) => {
    
    //  Set allow cross domain 
    ctx.set("Access-Control-Allow-Origin", "*");
    ctx.set("Access-Control-Allow-Methods", "PUT, POST, GET, DELETE, OPTIONS");
    //  Request header Settings 
    ctx.set(
        "Access-Control-Allow-Headers",
        `Content-Type, Content-Length, Authorization, Accept, X-Requested-With , yourHeaderFeild,x-token,sessionToken,token`
    );
    if (ctx.method == "OPTIONS") {
    
        ctx.body = 200;
    } else {
    
        next();
    }
})

The configuration server supports breakpoint continuation

To configure Koa Static resources support breakpoint continuation Accept-Ranges and Content-Range

copyright notice
author[thankseveryday],Please bring the original link to reprint, thank you.
https://en.qdmana.com/2022/132/202205120527258210.html

Random recommended