Node基础入门(一)

826 阅读9分钟

NodeJs 概述

Node.js 诞生于2009年,Node.js采用C++语言编写而成,是 一个Javascript的运行环境。Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境 ,让JavaScript的运行脱离浏览器端,可以使用JavaScript语言书写服务器端代码。

nodejs = ECMAScript + 各种基于ES的模块(net,http,FileSystem)

  • server 服务端开发(通过网络提供各种数据)
  • 工具:vue-cli,create-react-app
  • 桌面端(electorn, nw):vscode

那么js可以简单理解为

JavaScript = ECMAScript + DOM + BOM。

特点

  • 单线程
  • 非阻塞 I/O
    • 访问文件
    • 网络请求
    • 数据库查询
    • 键盘/鼠标交互
  • 事件驱动

common.js 规范

  • CommonJS就是为JS的表现来制定规范,因为js没有模块的功能所以CommonJS应运而生,它希望js可以在任何地方运行,不只是浏览器中。

    1、创建自定义模块

    • 引入一个文件 形式模块

      home.js执行文件

      //通过require来引入
      require("./aModule"); //注意一定要有"./",文件后缀可加可不加。
      

      amodule.js文件

      console.log("我是amodule模块111");
      
    • 引入文件夹形式模块

      • home.js执行文件
      require("./aModuledir"); //必须加"./"
      

      ​ aModuleDir里的index.js文件,会自动查找文件夹下的index.js文件执行

      console.log("我是aModule模块文件夹");
      
      • 当然也可以配置默认启动文件,在文件夹内新建package.json来指定执行文件
      {
        "name":"aModule",
        "version":"1.0.0",
        "main":"test.js"
      }
      
  • 自定义模块的按需导出

    通过module.exports 导出;

    module.exports = {
        a:"我是a的值",
        b(){
            console.log("我是导出的b函数");
        }
    }
    

    引入导出文件

    let mymodule = require("bModule");
    console.log(mymodule.a);
    mymodule.b();
    

    或者 通过 exports来导出

    exports.fn = function(){
        console.log("我是fn函数");  
    }
    

    导入文件

    let myfn = require("bModule").fn;
    myfn();
    // 或者 通过解构赋值 
    let { fn } = require("bModule");
    fn();
    
  • 模块加载的优先级 ,先文件再目录;

2、内置模块;

nodejs内置模块有:Buffer,C/C++Addons,Child Processes,Cluster,Console,Cr

ypto,Debugger,DNS,Domain,Errors,Events,File System,

Globals,HTTP,HTTPS,Modules,Net,OS,Path,Process,P unycode,Query Strings,Readline,REPL,Stream,String De coder,Timers,TLS/SSL,TTY,UDP/Datagram,URL, Utilities,V8,VM,ZLIB;内置模块不需要安装,外置模块需要安装;

3、第三方模块

第三方模块使用npm工具包下载,会放在node_module里面

http模块创建服务

NodeAPi

ECMAScript运行在服务器端,就可以提供服务。这个时候需要http 内置模块,来进行http的服务器开发。

//引入http模块
let http = require("http");
//创建一个服务器
let server = http.createServer((req,res)=>{
    
    console.log("hello");
    res.end("hello world");
})
//设置端口号
server.listen(3000);
  • http.createServer(callback)

    api

    callback --> 回调函数,当有客户端请求发送,并被当前server监听到了, 则会执行该函数。

    callback--> 两个参数 request ,response

    • 具体看第三点 服务器响应和客户端的请求

    • request: http.ClientRequest 类,request 类存储当前请求的客户端信息和方法

    • response: http.ServerResponse 类,response 类提供服务器响应相关的信息和方法

      • response.write() 回应客户端发送数据
      • response.end()告诉客户端,已经读写完毕。必须
  • server.listen(3000,callback)

    第一个参数是:端口号,默认8080

    callback--> 启动服务时候运行的函数

fs模块加载静态文件

  • fs是文件操作模块,所有文件操作都是有同步和异步之分,特点是同步会加上 "Sync" 如:异步读取文件 "readFile",同步读取文件 "readFileSync";

  • 读取到文件内容不一定是字符串,可能是图片视频等,那么它将他都转为buffer 二进制形式

  • 文件操作方法

    • 文件读取:
      • 异步读取,容易造成回调地狱
      let fs = require("fs");
      fs.readFile("1.txt",(err,data)=>{
          if(err){
              return console.log(err);
          }
          console.log(data.toString());
      })
      
      • 同步读取文件,
      let fs = require("fs");
      let res = fs.readFileSync("1.txt");
      console.log(res.toString());
      
    • 文件写入:
      let fs = require("fs");
      //flag配置  "a":追加写入,"w":写入,"r":读取
      fs.writeFile("2.txt","我是要写入的内容",{flag:"w"},err=>{
          if(err){
              return console.log(err);
          }
          console.log("写入成功");   
      })
      
    • 文件删除
      fs.unlink("2.txt",err=>{
          if(err){
              return console.log(err);
          }
          console.log("删除成功");
      })
      
    • 复制文件
      • 先读取文件再写入文件
      function mycopy(src,dest){
         fs.writeFileSync(dest,fs.readFileSync(src));
      }
      mycopy("1.txt","4.txt");
      
    • 修改文件名,目录也可以通过rename来操作
      fs.rename("1.txt","5.txt",function (err) {
          if(err){
              console.log(err);
          }else{
              console.log("修改成功");
          }
      });
      
    • 判断文件是否存在
      fs.exists("4.txt",function (exists) {
          console.log(exists);
      })
      
  • 目录操作方法

    // 创建目录
    fs.mkdir("11",err=>{
        if(err){
            return console.log(err);
        }
        console.log("创建成功");
    })
    修改目录名称
    fs.rename("11", "22", err => {
        if (err) {
            return console.log(err);
        }
        console.log("修改成功");
    })
    读取目录;
    fs.readdir("22",(err,data)=>{
        if(err){
            return console.log(err);
        }
        console.log(data);
    })
    删除目录(空文件夹/目录)
    fs.rmdir("11",err=>{
        if(err){
            return console.log(err);
        }
        console.log("删除成功");
    })
    
    判断文件或者目录是否存在
    fs.exists("index.html",exists=>{
        console.log(exists);
    })
    获取文件或者目录的详细信息;
    fs.stat("index.html",(err,stat)=>{
        if(err){
            return console.log(err);
        }
        // console.log(stat);
        // 判断文件是否是文件
        // let res = stat.isFile();
        // 是否是一个文件夹;
        let res = stat.isDirectory();
        console.log(res);
    })
    
    // 删除非空文件夹;
    // 先把目录里的文件删除-->删除空目录;
    // 22
    function removeDir(path){
       let data = fs.readdirSync(path);
        // ["33","1.txt","2.html"];
       for(let i=0;i<data.length;i++){
            // 是文件或者是目录; --->?文件 直接删除?目录继续查找;  
            let url = path + "/" + data[i];
            let stat =  fs.statSync(url);
            if(stat.isDirectory()){
                //目录 继续查找;
                removeDir(url);
            }else{
                // 文件 删除
                fs.unlinkSync(url);
            }
       }
        //  删除空目录
       fs.rmdirSync(path);
    }
    removeDir("22");
    

服务器响应和客户端的请求

response

客户端访问的地址(url)与后端的文件不是一对一关系,它们只是一种虚拟映射关系,这个关系是我们后端程序根据实际情况去返回的。

例如我这里的情况,在客户端无论地址写后面写什么都是虚拟地址,返回的相应都是./template/index.html 这个服务器端的这个实际地址的数据。

而客户端根据不同地址返回不同网页这个动作,其实是需要在服务器端设置。做一个一一对应。例如:

http://localhost:3000/index.html 客户端发起这个请求,那么后端设置 path/index.html

http://localhost:3000/part1.html 客户端发起这个请求,那么后端设置 path/part1.html

...

这样才能根据客户端虚拟地址的不同返回不同的页面,不然就只能是同一个页面

http://localhost:3000/(虚拟地址)

const http = require('http');
//引入fs 模块
const fs = require('fs');

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

    const content = fs.readFileSync('./template/index.html')
    res.write(content);
    res.end();
})

server.listen(3000,()=>{
    console.log('服务启动成功, 地址:http://localhost:3000');
});

request

我们页面发起请求的时候有有地址请求,还有就是对静态文件的请求。例如css 文件等。那么request 参数里面有个一个url的属性可以读取客户端发过来的请求。

message.url

例如:

<!DOCTYPE html>
<html lang="en">
<head>
   <meta charset="UTF-8">
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   <title>Title</title>
   <link rel="stylesheet" href="./css/index.css">
</head>
<body>
   <h1>Hello world!!</h1>
</body>
</html>

//css
body{
    background-color: antiquewhite;
}


//服务端
const http = require('http');
//引入fs 模块
const fs = require('fs');

let server = http.createServer((req,res)=>{
	
    let url = req.url;
    console.log(url);
    const content = fs.readFileSync('./template/index.html')
    res.write(content);
    res.end();
})

server.listen(3000,()=>{
    console.log('服务启动成功, 地址:http://localhost:3000');
});

当我们这样发起请求时候会返回这两个结果。

/
/css/index.css

但是我们 const content = fs.readFileSync('./template/index.html')这里已经写死,无论什么请求都返回这个文件。所以css在这里并没有起作用。于是我们可以猜想,可以使用switch case 语法解决。

这样修改后就能显示正确的样式

    let url = req.url;
    let content = ''
    console.log(url);

    switch (url) {
        case "/":
            content = fs.readFileSync('./template/index.html')
            break;
        case "/css/index.css":
            content = fs.readFileSync('./template/css/index.css');
            break;
    }

前后端静态资源交互

上面的例子可以处理简单的请求,但是实际中,一个网页有多图片、文件等静态资源。不可能一一对应。所以我们可以和后端制定统一的规则读取静态文件。例如约定以/public开头的请求就是要读取静态文件。实际的静态文件存储在服务器的static

当然我们的静态页面可以放进我们的static文件里面。那么访问静态的页面的时候,我们需要把地址修改成

http://localhost:3000/public/index.html

if(url.startsWith('/public'))
{
   url = url.replace(/^\/public/g,'\\static');
    //console.log('static',__dirname + url);
    content = fs.readFileSync(__dirname + url);
    res.write(content);

}

请求头设置header

每次交换的数据(请求、响应),我们称为:报文

每一个报文数据包含:行、头、正文 ['行', '头', '正文']

正常用户看到的是正文,但是服务器给我们发送信息除了正文,还有行信息和头信息

  • 行信息

    sv1O6f.png

  • 头信息

    一般用于额外的数据处理。客户端请求带过去服务器端的信息,还有就是服务器端带过来的信息。因为信息以二进制方式传递,那么我们在发送信息的时候要设置头信息,告诉浏览器这是个什么文件,让浏览器引擎解析。

    例如这段代码,如果不设置res.setHeader('Content-Type','text/html;charset=utf-8');浏览器将会把中文解析为乱码。

    else {
        res.setHeader('Content-Type','text/html;charset=utf-8');
        res.write('欢迎来到我的nodeJs');
    }
    

    当然头信息还有很多,我们以后会慢慢补充。

相关工具包

yarn、cnpm、nvm、nrm工具介绍

  • npm

    • NPM(Node Package Manager) 官网的地址是 npm官网

      • npm常用指令;
        • npm init:引导创建一个package.json文件
        • npm help(npm -h) :查看npm帮助信息
        • npm version (npm -v) : 查看npm版本;
        • npm search:查找
        • npm install (npm i):安装 默认在当前目录,如果没有node_modules 会创建文件夹;
          • npm install module_name -S 或者--save 即 npm install module_name --save 写入dependencies
          • npm install module_name -D 或者 —save-dev 即 npm install module_name --save-dev 写入devDependencies
          • npm install module_name -g 全局安装(命令行使用)
          • 指定版本安装模块 npm i module_name @1.0 通过 "@"符号指定;
        • npm update(npm -up):更新
        • npm remove 或者 npm uninstall:删除
        • npm root 查看当前包安装的路径 或者通过 npm root -g 来查看全局安装路径;
  • nrm

    管理源的工具。管理下载地址的,能测试延迟等功能

    www.jianshu.com/p/5961eefcc…

  • cnpm

    切换下载镜像地址的,cnpm会更快一点,但是会有延迟性

    www.oschina.net/p/cnpm?hmsr…

  • yarn 包管理工具

    yarn 和npm 差不多现在,yarn 是解决npm 旧版本问题的

npm install -g yarn
  • nvm

    • nvm 是 mac 环境下管理 nodejs 的工具。在 windows 环境下推荐使用 nvmw 或者 nvm-windows;

    • 安装 NVM

      • 在安装 nvm 之前需要一个 c++编译器,在 mac 上可以安装 Xcode 命令工具(已经安装可以忽略)
      xcode-select --install
      
      • 使用 curl 安装
      curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.34.0/install.sh | bash
      
      • 或者使用 wget 来安装
      wget -qO- https://raw.githubusercontent.com/creationix/nvm/v0.34.0/install.sh | bash
      
    • NVM github 的地址可以查看最新版本

    • NVM 常用指令;

      nvm --version查看版本

      nvm install stable //安装最新稳定版nodejs

      nvm install 8.11.1 //安装指定版本

      nvm install 8.11 //安装 8.11.x系列最新版本

      nvm ls-remote //列出远程服务器上所有可用的版本

      nvm use 8.11.1 //切换到8.11.1版本

      nvm use 8.11 //切换到8.11.x最新版本

      nvm use node //切换到最新版本

      nvm alias default node //设置默认版本为最新版本

      nvm ls //列出所有已经安装的版本