docker desktop创建node:18 server

Posted _less is more

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了docker desktop创建node:18 server相关的知识,希望对你有一定的参考价值。

1、创建node18容器

docker run --rm -it -v "D:/AIHUB_workSpace/USC-courses/EE547":/usr/src/app -p 3000:3000 node:18 /bin/bash

如果没有会自动下载node:18的image,然后自动进入container内部,退出会自动删除container,该image大小为990.67MB

注:之后使用npm install也在/usr/src/app下进行,如果在进入container时的默认根目录进行,可能会出现如Tracker "idealTree" already exists的错误

2、查看版本

root@f2fd36a194ca:/# node -v
v18.9.0
root@f2fd36a194ca:/# npm -v
8.19.1

3、创建index.js文件
因为本地文件夹已经mount到了container内部,在windows该文件夹下直接添加文件便能在container内部看到

'use strict';
const http = require('http');
const server = http.createServer(function (req, res) 
 if (req.url == '/') 
 res.writeHead(200,  'Content-Type': 'text/html' );
 res.write('<html><body>Hello, node.js!</body></html>');
 res.end();
 
);
server.listen(3000);
console.log('Server started, port 3000');

此时/usr/src/app下应该有index.js文件
到/usr/src/app启动该server

root@f2fd36a194ca:/usr/src/app# node index.js
Server started, port 3000

4、请求该端口
因为映射了端口3000到container内部的3000
因此可以直接打开浏览器

http://127.0.0.1:3000/

便能看到Hello, node.js!的返回结果

或者如果在Windows安装了curl,可以打开cmd,便能有如下结果

C:\\Users\\ASUS>curl http://127.0.0.1:3000/
<html><body>Hello, node.js!</body></html>

5、使用nodemon

当用该命令启动index.js时,如果nodemon检测到index.js文件有改变,会自动重新启动服务,便于快速开发

在container内部安装

npm install nodemon

如果这行安装不了,用

npm install -g nodemon

因为我们使用nodemon一般是在命令行使用,所以加上-g安装的nodemon才提供在命令行中使用该库的工具,否则就会提示找不到nodemon。如果我们只需要在程序中调用该包,则不用加-g即可

如果不小心关掉了cmd界面用该命令重新进入container

docker exec -it f2fd36a194cad7c294edbcbe04f5ae2bce003cb52c8d55b30f320ead6367af0c /bin/bash

现在用nodemon启动index.js

nodemon index.js

http://127.0.0.1:3000/secret访问服务器,会发现没有反应,也不会自动结束,而是处于等待状态

现在进化一下index.js如下,使之可以返回404

'use strict';
const http = require('http');
const PORT = 3000;
const server = http.createServer((req, res) => 
 if (req.url == '/') 
 res.writeHead(200,  'Content-Type': 'text/html' );
 res.write('<html><body>Hello, node.js!</body></html>');
 res.end();
  else 
 res.writeHead(404);
 res.end();
 
);
server.listen(PORT);
console.log(`Server started, port $PORT`);

当我们在Windows端修改了该文件,nodemon会自动检测到文件改变,然后自动重新启动

现在访问不存在的路径会自动返回404

注:自动启动功能在Windows10上结合docker desktop,并没有测试成功,仍需手动重启,可能有一些兼容性原因; 一个StackOverflow上的解决方法是用nodemon --legacy-watch index.js启动,--legacy-watch会将nodemon听(listen)文件系统事件的行为变成轮询(poll),这样理论上会慢一点,但可以保证能够检测到文件的改变并自动重启

6、一个更好的index.js

'use strict';
const http = require('http');

const PORT = 3000;

const server = http.createServer((req, res) => 
    let respBody = '';
    let contentType = 'text/html';
    let httpCode = 404;

    try 
        switch (req.method.toLowerCase()) 
            case 'get':
                // can add logs to see elements
                console.error(req.url)
                const urlPath = req.url.split('/');

                if (req.url === '/')  
                    httpCode = 200;
                    respBody = 'Welcome home';
                 else if (urlPath.length === 2 && urlPath[1] === 'greet') 
                    httpCode = 200;
                    respBody = '<html><body>Hello, node.js!</body></html>';
                 else if (urlPath.length === 3 && urlPath[1] === 'greet' && urlPath[2].match(/^a-z+$/)) 
                    httpCode = 200;
                    respBody = `<html><body>Hello $urlPath[2], node.js!</body></html>`;
                
                break;
            case 'post':
                // add me
                break;
        
     catch (err) 
        respBody = `Error: $err.message`;
        httpCode = 500;
    

    res.writeHead(httpCode,  'Content-Type': contentType );
    res.write(respBody);
    res.end();
);

server.listen(PORT);

console.log(`Server started, port $PORT`);

调试,-v可以输出完整的接受到的包信息

curl -v http://127.0.0.1:3000/greet

7、一个神奇的报错
[nodemon] app crashed - waiting for file changes before starting...

其实是因为我的js里有个语法错误,一个括号没有闭合而已,和文件有没有改变没有关系

8、使用url包,自动解析url,更易于应对更加复杂的url

'use strict';
const http = require('http');

const PORT = 3000;

// const qs = require('querystring');
const url = require('url');

const server = http.createServer((req, res) => 
    let respBody = '';
    let contentType = 'text/html';
    let httpCode = 404;

    console.error(req.url)
    const reqUrl = url.parse(req.url, true);
    console.error(reqUrl)
    const urlPath = reqUrl.pathname.split('/');

    console.error(urlPath)

    if (urlPath.length === 2 && urlPath[1] === 'greet') 
        httpCode = 200;
        respBody = reqUrl.query.name ? `<html><body>Hello $reqUrl.query.name, node.js!</body></html>` :
        '<html><body>Hello, node.js!</body></html>';
     else  

    res.writeHead(httpCode,  'Content-Type': contentType );
    res.write(respBody);
    res.end();
)

server.listen(PORT);
// 这行代码将被执行,因为js的异步机制,而在python中则不会执行到这
console.log(`Server started, port $PORT`);

9、express中间件

我猜测express是基于html包做了封装,或者实现了类似html包的功能,也能提供服务,监听端口,并进行路由,以及其他更强大的功能

安装express,因为不需要在terminal使用,因此不用加-g(globally),直接locally安装即可

npm install express

index.js文件

'use strict';
const express = require('express');
const app = express();

app.get('/greet', (req, res) => 
    res.writeHead(200,  'Content-Type': 'text/html' );
    res.write('<html><body>Hello, express!</body></html>');
    res.end();
);

app.listen(3000);

可见这里我们没有处理除了/greet以外的路径,但express会自动处理此问题,返回404,不会像html包那样需要自己处理

10、静态内容

创建public文件夹,放入index.html

<html>
 <body>
 <p>
 Hello, static page!
 </p>
 </body>
</html>

在index.js添加app.use那一句

'use strict';
const express = require('express');
const app = express();

app.use(express.static('public'));

app.get('/greet', (req, res) => 
    res.writeHead(200,  'Content-Type': 'text/html' );
    res.write('<html><body>Hello, express!</body></html>');
    res.end();
);

app.listen(3000);

此时访问直接访问http://127.0.0.1:3000时就不会报错,会自动返回该index.html

添加图片:在public下创建image文件夹,并添加一张图

在index.html中使用

<html>
 <body>
 <p>
 Hello, static page!
 </p>
 <div id="mascot">
 <a href="https://www.google.com/search?q=silly+cats">
 <img src="/image/deeplearning.jpg" />
 </a>
 </div>
 </body>
</html>

11、url传参

'use strict';
const express = require('express');
const app = express();

app.use(express.static('public'));

app.get('/greet', (req, res) => 
 res.writeHead(200,  'Content-Type': 'text/html' );
 res.write(`<html><body>Hello, $req.query.first_name $req.query.last_name</body></html>`);
 res.end();
);
app.get('/greet/:firstName/:lastName', (req, res) => 
 res.writeHead(200,  'Content-Type': 'text/html' );
 res.write(`<html><body>Hello, $req.params.firstName $req.params.lastName</body></html>`);
 res.end();
);

app.listen(3000);

比如

http://127.0.0.1:3000/greet?first_name=1&last_name=xixi
得到Hello, 1 xixi

http://127.0.0.1:3000/greet/xixi/haha
得到Hello, xixi haha

12、npm install express-list-endpoints

查看定义的路由

index.js

'use strict';
const express = require('express');
const listEndpoints = require('express-list-endpoints');

const app = express();

console.log(listEndpoints(app));

app.use(express.static('public'));

app.get('/greet', (req, res) => 
 res.writeHead(200,  'Content-Type': 'text/html' );
 res.write(`<html><body>Hello, $req.query.first_name $req.query.last_name</body></html>`);
 res.end();
);
app.get('/greet/:firstName/:lastName', (req, res) => 
 res.writeHead(200,  'Content-Type': 'text/html' );
 res.write(`<html><body>Hello, $req.params.firstName $req.params.lastName</body></html>`);
 res.end();
);

console.log(listEndpoints(app));

app.listen(3000);

得到结果,可见定义后输出了我们定义的路由

[  path: '', methods: [], middlewares: []  ]
[
   path: '/greet', methods: [ 'GET' ], middlewares: [ 'anonymous' ] ,
  
    path: '/greet/:firstName/:lastName',
    methods: [ 'GET' ],
    middlewares: [ 'anonymous' ]
  
]

13、uuid

一个debug小技巧,用nodemon启动index.js如果有bug很难看出问题,而换成node启动则会直接报错提示,便于调试

安装uuid

npm install uuid

index.js文件

'use strict';

const uuid = require('uuid');
const express = require('express');
const app = express();

app.use(express.static('public'));


app.get('/greet', (req, res) => 
    req.my_data = 
        start_at: new Date(),
        request_id: uuid.v4()
    ;

    console.log(`Request complete -- path:$req.path, status:$res.statusCode, id:$req.my_data.request_id`)

    res.writeHead(200,  'Content-Type': 'text/html' );
    res.write(`<html><body>Hello, $req.query.first_name $req.query.last_name</body></html>`);
    res.end();
);

app.listen(3000);

也可以把greet中的语句分开写,但需要加入next(),不然不会执行下一个greet,而是直接结束该函数的执行

'use strict';

const uuid = require('uuid');
const express = require('express');
const app = express();

app.use(express.static('public'));

app.get('/greet', (req, res, next) => 
    req.my_data = 
        start_at: new Date(),
        request_id: uuid.v4()
    ;

    next();
);

app.get('/greet', (req, res, next) => 

    console.log(`Request complete -- path:$req.path, status:$res.statusCode, id:$req.my_data.request_id`)
    next();
);

app.get('/greet', (req, res, next) => 

    res.writeHead(200,  'Content-Type': 'text/html' );
    res.关于在k8s-desktop-for-mac如何坚持优雅地填坑

访问docker desktop创建的Hyper-v虚拟机DockerDesktopVM

Docker zookeeper 集群 for Docker desktop (win)

Docker Desktop 可以直接启用Kubernetes 1.25 了

Docker Desktop安装本地Kubernetes集群

Docker Desktop 现已支持 Linux