zoukankan      html  css  js  c++  java
  • Node_进阶_2

    第二天

    一、复习:

    Node.js开发服务器、数据、路由。本地关心效果,交互。

    Node.js实际上是极客开发出的一个小玩具,不是银弹。有着别人不具备的怪异特点:

    单线程、非阻塞I/O、事件驱动。 实际上是一个特点。

    首先,Node不为每个用户开辟一个线程,所以非常极端的选择了单线程。

    单线程,要照顾所有的用户,必须有非阻塞I/O否则一个人的I/O就把别人、自己都阻塞了。

    一旦有非阻塞I/O,一个人如果I/O去了,就会放弃CPU的使用权,换成另一个人使用CPU(或者执行此人后面的语句)。所以CPU的利用率是100%。第一个人I/O结束了,就要用事件来通知线程,执行回调函数。此时必须有事件环,就有一个排队调度机制,Node中有超过半数的C++代码,在搭建事件环。

    Node.js和别的老牌3P不一样:

    1)     没有自己的语法,使用V8引擎,所以就是JS。V8引擎解析JS的,效率非常高,并且V8中很多东西都是异步的。Node就是将V8中的一些功能自己没有重写(别人做了,自己就站在巨人肩膀上),移植到了服务器上。

    2)     没有web容器,就是安装配置完成之后,没有一个根目录。

    汇编语言 暴露几个API => C语言 暴露几百个API => 高级语言 暴露更多API

    系统中,80端口,就是默认的http端口,所以当没有端口号的时候就默认80端口。

    (https是443)

    之前写了一个静态服务器,但是其实不是很完善,虽然对mime类型有判断了,但是返回的都是200状态码。304状态码表示已经存在这个文件,实现的机制是用cookies来给文件打标记,302表示重定向。这些都没有实现.(顺带一提)

    二、模块

    模块的概念

    ·在Node.js中,以模块为单位划分所有功能,并且提供了一个完整的模块加载机制,这时的我们可以将应用程序划分为各个不同的部分。

    不可能用一个js文件去写全部的业务,肯定要有MVC。

    ·狭义的说,每一个JavaScript文件都是一个模块,而多个JavaScript文件之间可以相互require,他们共同实现了一个功能,他们整体对外,又称为一个广义上的模块。

    ·Node.js中,一个JavaScript文件中定义的变量、函数,都只在这个文件有效。当需要从模块外部引用这些变量、函数时,必须使用exports对象进行暴露。使用者要用require()命令引用这个JS文件。

    var msg = ‘你好’

    var info = ‘呵呵’

    exports.msg = msg

    msg这个变量是一个js文件内部才有作用域的变量。

    使用者:

    var foo = require(‘./test/foo.js’)

    console.log(foo.msg);

    暴露与引用。js文件中可以用exports暴露很多东西,比如函数、变量。

    相当于增加了顶层变量。所有的函数、变量都要从这个顶层变量走。

    Node中,js文件和js文件,就是被一个个exports和require构建称为网状依赖的。

    不是像HTML文件中从上往下依赖的。

    在js中可以将一个类暴露出去,然后进行引用。

    a.js

    function People(name,sex,age)

    {

    this.name = name;

    this.sex = sex;

    this.age = age;

    }

    People.prototype = {

       SayHello:function(){

        console.log(this.name+this.sex+this.age);

    }

    }

    //直接暴露出来

    module.exports = People;

    b.js:

    var People = require(‘./a.js’);

    var xiaoming = new People(‘xiaoming’,12,’男’);

    xiaoming.sayHello();

    文件夹模块和package文件

    如果require(‘a.js’)这样不写出路径

    会自动默认的加载node_modules文件夹中的内容。

    如果当前层没有,他就逐级遍历哪一层有Node_modules文件夹。

    甚至可以放到NODE_PATH环境变量的文件夹中。

    计算机-高级系统设置-环境变量-新建系统遍历 名字叫NODE_PATH。

    ·也可以使用文件夹来管理模块,比如:

     var bar = require(‘bar’)

     那么Node.js将会去寻找node_modules目录下的bar文件夹中的Index.js去执行。

     可以自定义这个文件,需要建立package.json然后为main项设定。

    这样require(‘bar’)文件夹的时候,就会去读取这个app.js

    NPM

    我们刚才学习了,模块就是一些功能的封装,所以一些成熟的、经常使用的功能,都有人封装成为了模块。

    www.npmjs.com

    去社区搜索需求,然后点进去看api

    ..

    1. 我们的依赖包,可能在随时更新,我们永远想保持更新。
    2. 项目越来越大的时候,给别人看的时候,没有必要再次共享我们引用的第三方模块。

    所以我们用package.json来管理我们的依赖。

    package.json的

    ‘dependency‘中的^符号确保更新时这一位版本不变,其他的位数在install时候会自动更新。因为社区开发者每个人对自己的版本更新都有不同的定义。有时虽然大版本没变,但是小版本号的更新也可能带来了巨大的变化。会导致程序挂掉。所以出现了packagelock.json来锁定到特定的版本。

    路径

    文件的操作一定要用绝对路径,因为如果在a.js中require了一个b.js,这个js中有用fs读取了一个相对路径,那么读取出来的路径会有错误,因为node a.js的时候是以a为相对目录的。

    require()别的文件的时候,会执行这个js文件。

    实际上他会做一次绑定,把对象中的export对象绑定给承接的变量。

    注意:require()中的路径是从当前js文件出发找到别人。所以,桌面上有一个a.js,test文件夹中有一个b.js和c.js

    a要引用b:

    var a = require(‘./test/b.js‘);

    b要引用c:

    var b = require(‘./c.js’)

    但是,fs等其他的模块用到路径的时候都是相对于入口文件的。

    所以,如果test文件夹中,有一个1.txt,那么在b.txt中想读取这个文件,请使用绝对路径。

    (使用__dirname)

    狭义的讲,一个js文件就是一个模块。

    广义的讲,一个文件夹(或者是带package.json的文件夹)也是一个模块,因为会去读取文件夹内的index.js(或者package.json中的main:’入口文件.js’)

    三、post请求

    post请求

    示例:

    (req.addListener == req.on)

    a.js:

    const http = require('http');

    const querystring = require('querystring');

     

    var server = http.createServer((req, res) => {

     

        //如果你的访问地址是这个,并且请求类型是post

        if (req.url == '/dopost' && req.method == 'POST') {

     

            var alldata = "";

     

            //不断的往事件环里去加载这个事件

            //接受了一小段,可能就给别人去服务了。防止一个过大的表单阻塞了整个线程

            req.on('data', (chunk) => {

                alldata += chunk;

            });

     

            req.on('end', (chunk) => {

     

                var datastring = alldata.toString();

                res.end('success');

     

                //将datastring转为一个对象

                var dataObj = querystring.parse(datastring, null, null,

                );

     

                console.log(dataObj);

                console.log(dataObj.name);

                console.log(dataObj.sex);

     

            })

     

        }

    });



    server.listen(3000);

     

    aa.html:

    <!DOCTYPE html>

    <html lang="en">

     

    <head>

        <meta charset="UTF-8">

        <meta name="viewport" content="width=device-width, initial-scale=1.0">

        <meta http-equiv="X-UA-Compatible" content="ie=edge">

        <title>Document</title>

    </head>

     

    <body>

     

        <form action="http://127.0.0.1:3000/dopost" method="POST">

     

            <p>

                姓名:

                <input type="text" name='name'>

            </p>

     

            <p>

                性别:

                <input type="radio" name='sex' value='女' id='female'>

                <label for="female">女</label>

                <input type="radio" name='sex' value='男' id='male'>

                <label for="male">男</label>

            </p>

     

            <p>

                爱好:

                <input type="checkbox" name='hobby' value='睡觉'>睡觉

                <input type="checkbox" name="hobby" value="吃饭">吃饭

                <input type="checkbox" name="hobby" value="足球">足球

            </p>

     

            <input type="submit" value="提交">

     

        </form>

     

    </body>

     

    </html>

     

    如果这里有一个图片上传的input 最后alldata.toString()以后会是undefined ,所以,对于图片要做一个二进制的文件的处理。

     

    formidable

    formidable是一个node.js的表单模块

     

    看以下npm.js网址上对这个模块的介绍:

    Purpose

    A Node.js module for parsing form data, especially file uploads.

    This module was developed for Transloadit, a service focused on uploading and encoding images and videos. It has been battle-tested against hundreds of GB of file uploads from a large variety of clients and is considered production-ready.

    (图为API的使用)

     

    可以看到,把所有请求的表单域用fields(字段)表示,把所有的文件用files(文件)来表示。

     

     

    aa.html:

    <!DOCTYPE html>

    <html lang="en">

     

    <head>

        <meta charset="UTF-8">

        <meta name="viewport" content="width=device-width, initial-scale=1.0">

        <meta http-equiv="X-UA-Compatible" content="ie=edge">

        <title>Document</title>

    </head>

     

    <body>

     

        <form action="http://127.0.0.1:3000/dopost" enctype="multipart/form-data" method="POST">

     

            <p>

                姓名:

                <input type="text" name='name'>

            </p>

     

            <p>

                性别:

                <input type="radio" name='sex' value='女' id='female'>

                <label for="female">女</label>

                <input type="radio" name='sex' value='男' id='male'>

                <label for="male">男</label>

            </p>

     

            <p>

                爱好:

                <input type="checkbox" name='hobby' value='睡觉'>睡觉

                <input type="checkbox" name="hobby" value="吃饭">吃饭

                <input type="checkbox" name="hobby" value="足球">足球

            </p>

     

            <p>

                图片:

                <input type="file" name='tupian'>

            </p>

     

            <input type="submit" value="提交">

     

        </form>

     

    </body>

     

    </html>

     

     

    12.js:

    //formidable

    1.js:

    const http = require('http');

    const querystring = require('querystring');

    const formidable = require('formidable');

    const util = require('util');

     

    var server = http.createServer((req, res) => {

     

        if (req.url == '/dopost' && req.method == 'POST') {

     

            //create a new incoming form

            var form = new formidable.IncomingForm();

            //设置文件上传存放的地址

            form.uploadDir = "./uploads";

     

            //执行里面回调函数的时候,表单已经全部接收完毕了。

            form.parse(req, function (err, fields, files) {

     

                if (err) {

                    throw err;

                }

     

                //所有的文本域、单选框,都在fileds里面存放;

                //所有的文件与,都在files内存放。

                //util.inspect 相当于console.log这个对象

                console.log(util.inspect({ fields: fields, files: files }));

     

                res.writeHead(200, { 'content-type': 'text/html;charset=UTF-8' });

                res.write('received upload: ');

                res.end('Success');

     

            });

            return;

        }

    }).listen(3000);

     

     

    在这节课学到的一个比较重要的东西是如果上传图片的时候,在form标签里一定要加enctype="multipart/form-data"

     

     

     

    上传改名

    原生的POST比较复杂,要写两个监听。

    所以用第三方的formidable比较方便。

     

    下面继续上面的案例来做,上传的文件名改名为2018050812323(时间+随机数)这样。

     

    这里顺带介绍了一下silly-datetime插件 可以格式化的生成时间

    https://www.npmjs.com/package/silly-datetime

    (非常好用)

     

    formidable里面生成的fields与files的数据结构是这样的:

    13.js:

    //上传图片 文件名是当前时间

     

    //formidable

     

    const http = require('http');

    const querystring = require('querystring');

    const formidable = require('formidable');

    const util = require('util');

    const fs = require('fs');

    const sd = require('silly-datetime');

    const path = require('path');

     

    var server = http.createServer((req, res) => {

     

        if (req.url == '/dopost' && req.method == 'POST') {

     

            //create a new incoming form

            var form = new formidable.IncomingForm();

            //设置文件上传存放的地址

            form.uploadDir = "./uploads";

     

            //执行里面回调函数的时候,表单已经全部接收完毕了。

            form.parse(req, function (err, fields, files) {

     

                if (err) {

                    throw err;

                }

     

                //所有的文本域、单选框,都在fileds里面存放;

                //所有的文件与,都在files内存放。

                //util.inspect 相当于console.log这个对象

                console.log(util.inspect({ fields: fields, files: files }));

     

                //时间,使用的第三方模块,silly-datetime

                var ttt = sd.format(new Date(), 'YYYYMMDDHHmm');

                var ran = parseInt(Math.random() * 89999 + 10000);

                var extname = path.extname(files.tupian.name);

     

                //执行该名

                var oldpath = __dirname + '/' + files.tupian.path;

                //新的路径由三个部分组成: 时间戳、随机数、扩展名

                var newpath = __dirname + '/uploads/' + ttt + ran + extname;

     

                //改名

                fs.rename(oldpath, newpath, (err) => {

     

                    if (err) throw Error('改名失败');

     

                    res.writeHead(200, { 'content-type': 'text/html;charset=UTF-8' });

                    res.end('成功');

     

                });

            });

     

        } else if (req.url == '/') {

            //呈递form.html页面

            fs.readFile('./aa.html', (err, data) => {

                res.writeHead(200, { 'Content-type': 'text/html;charset=UTF-8' });

                res.end(data);

            });

        } else {

            res.writeHead(404, { 'Content-type': 'text/html;charset=UTF-8' });

            res.end('404');

        }

    }).listen(3000);

     

     

    aa.html:

    <!DOCTYPE html>

    <html lang="en">

     

    <head>

        <meta charset="UTF-8">

        <meta name="viewport" content="width=device-width, initial-scale=1.0">

        <meta http-equiv="X-UA-Compatible" content="ie=edge">

        <title>Document</title>

    </head>

     

    <body>

     

        <form action="http://127.0.0.1:3000/dopost" enctype="multipart/form-data" method="POST">

     

            <p>

                姓名:

                <input type="text" name='name'>

            </p>

     

            <p>

                性别:

                <input type="radio" name='sex' value='女' id='female'>

                <label for="female">女</label>

                <input type="radio" name='sex' value='男' id='male'>

                <label for="male">男</label>

            </p>

     

            <p>

                爱好:

                <input type="checkbox" name='hobby' value='睡觉'>睡觉

                <input type="checkbox" name="hobby" value="吃饭">吃饭

                <input type="checkbox" name="hobby" value="足球">足球

            </p>

     

            <p>

                图片:

                <input type="file" name='tupian'>

            </p>

     

            <input type="submit" value="提交">

     

        </form>

     

    </body>

     

    </html>

     

    这个项目可以运行在服务器上,运行在局域网中,然后让别人给你的电脑上传文件,很棒。

     

     

    四、模板引擎

    ejs模板引擎

     

    <a href="<%=url%>"><img src="<%=imageURL%>" alt=""></a>

    数据绑定,就成为一个完整的html字符串了。

    前台的模板,我们现在要学习的是后台的模板。

     

    后台模板,著名的有两个,第一个叫做ejs,第二个叫做jade

     

    是npm第三方的包

     

     

    先说ejs

    Embedded JavaScript templates

    (嵌入式javascript模板引擎)

     

    index.ejs:

    <!DOCTYPE html>

    <html lang="en">

     

    <head>

        <meta charset="UTF-8">

        <meta name="viewport" content="width=device-width, initial-scale=1.0">

        <meta http-equiv="X-UA-Compatible" content="ie=edge">

        <title>Document</title>

    </head>

     

    <body>

        <h1>好高兴啊,今天我买了一个iphone

            <%= a %>s</h1>

     

        <ul>

           <%for(var i = 0;i<news.length;i++){%> 

            <li><%= news[i]%></li>

            <% }%>

        </ul>

     

    </body>

     

    </html>

     

     

    1.js:

    const fs = require('fs');

    const ejs = require('ejs');

    const http = require('http');

     

    var server = http.createServer((req, res) => {

     

        fs.readFile('./views/index.ejs', (err, data) => {

     

            //绑定模板

            var template = data.toString();

            var dictionary = {

                a: 6,

                news: [21, 4, '哈哈']

            };

            var html = ejs.render(template, dictionary);

     

            res.writeHead(200, { 'Content-type': 'text/html;charset=UTF8' });

            res.end(html);

        });

     

    }).listen(2888);

     

     

     

    (模板引擎这种在服务器上把语句组织起来的形式将逐渐被淘汰了,因为代码组织起来太杂糅了。这种时代一去不复返了。)

     

    (未来后台只负责出数据)

     

    jade模板引擎

    ejs效率不高,因为是对字符串的处理 <% %>这种东西 下面介绍一下jade模板引擎

    http://jade-lang.com/ (jade:玉)

    www.npmjs.com/package/jade

    (这个语法有点像Python)

    这里不做介绍啦.

  • 相关阅读:
    Spring AOP 注解开发
    AOP的专业术语
    Java自定义注解的实现和应用
    Spring 声明式事务管理
    另一种线程安全机制:在事务管理中起到巨大作用的 ThreadLocal
    MySQL的二级索引
    数据库的范式化和反范式化
    MySQL为表字段添加索引
    mysql索引(二)----如何高效使用索引
    Alexnet网络
  • 原文地址:https://www.cnblogs.com/eret9616/p/9111063.html
Copyright © 2011-2022 走看看