前端与移动开发----Node.js----node核心模块

Node.js

初识Node.js

前台 - 浏览器运行JS代码

浏览器运行环境内置V8引擎(JS运行平台) - 把编写的JS代码来解析和执行

后台编程环境+语言

Java是个语言, JVM虚拟机, 是运行它的环境

Python是个语言, 也需要安装Python运行环境

PHP也是个语言, 需要安装PHP运行环境

前端与移动开发----Node.js----node核心模块_第1张图片

什么是Node.js

Node.js 的官网地址: https://nodejs.org/zh-cn/

Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境

其实Node本身是个软件环境, 但是因为它的语言和JavaScript近乎一样, 所以也叫它Node.js

Node脱离浏览器独立执行JS代码的软件环境

后台 - Node运行JS代码

前端与移动开发----Node.js----node核心模块_第2张图片

  • 浏览器是 JavaScript 的前端运行环境。
  • Node.js 是 JavaScript 的后端运行环境。
  • Node.js 中无法调用 DOM 和 BOM 等 浏览器内置 API

Node.js可以做什么

  • 基于 Express/Koa 框架(http://www.expressjs.com.cn/),可以快速构建 Web 应用
  • 基于 Electron 框架(https://electronjs.org/),可以构建跨平台的桌面应用
  • 基于 restify 框架(http://restify.com/),可以快速构建 API 接口项目
  • 读写和操作数据库, 辅助前端开发

Node.js环境安装

下载安装

必须在计算机上安装 Node.js 环境才行

安装包进入官网(中文),可以看到如下两个版本:

在这里插入图片描述

  • LTS 为长期稳定版,推荐安装 LTS 版本。建议

  • Current 为新特性尝鲜版,可能存在隐藏的 Bug 或安全性漏洞,不推荐企业开发使用

什么是终端

人机交互的一个窗口和工具, 只有程序员才会用到终端(也叫命令行工具)

之前我们学习过git 实际上那就是一个终端, 敲敲命令, 就能让电脑/软件帮助我们做一些事情

如何打开终端

windows

前端与移动开发----Node.js----node核心模块_第3张图片

查看已安装的Node.js的版本号

打开终端,在终端输入命令 node –v 后,按下回车键,即可查看已安装的 Node.js 的版本号

如果你能够看到版本号,说明你已经安装成功了。

1. 学习Node.js

1.0 hello, node.js

使用node命令执行JS文件

// 编写和执行js文件步骤
// 1. 新建js文件
// 2. 编写一些js代码(注意, 没有DOM和BOM)
// 3. 打开终端, 确保路径, 在此文件, 所在文件夹
// 4. 执行命令 node  文件名.js  回车 - node开始逐行执行js文件里代码, 输出结果到控制台

// node是独立(脱离浏览器)的一个环境, 使用node环境+命令来执行js文件
console.log("我是nodejs哦, 欢迎来学习我");

注意终端的路径,注意在此路径中,是否能找到你的js文件 / tab键可以补全剩下的路径文件名

常见问题

  • 路径一定要对, node后面跟的是文件路径
  • node命令和文件之间必须有空格
  • 不要执行 HTML 文件,node只能执行 JS 文件
  • 注意,最好不要使用多个终端

终端快捷键

前端与移动开发----Node.js----node核心模块_第4张图片


2. node核心模块

模块 = js文件, 里面是封装的基础 JS 代码

核心模块: node 系统自带的内置的 JS 文件

模块 = 以前学的插件

2.0 path模块

处理路径的模块

  • 中文文档 - http://nodejs.cn/api/path.html
  • 操作文件的时候经常要对文件的路径做处理,或者获取文件的后缀,使用 path 模块。
  • path 是 Node 本身提供的 API,专门用来处理路径。
  • path 仅仅用来处理路径的字符串,不一定存在对应的物理文件。

  • 使用方法

    • 加载模块

      // 使用核心模块之前,首先加载核心模块
      let path = require('path');
      // 相当于
      // let path = path内部暴露出的一个全局对象
      
      // 然后就可以使用path对象里的一些功能方法, 然后拿到返回值咯(如果有返回值)
      
    • 调用path模块中的方法,来处理相应的问题,下面列举path模块中的几个方法

      方法 作用
      path.basename(path) 返回 path 的最后一部分(文件名)
      path.dirname(path) 返回目录名
      path.extname(path) 返回路径中文件的扩展名(包含.)
      path.join([…paths]) 拼接路径
      path.resolve([…paths]) 基于当前工作目录拼接路径(绝对地址)
    const path = require('path');
        // basename - 获取路径最后一部分(一般用于文件名获取)
        console.log(path.basename("http://134.23.43.55/a/b/c/d.html")); // d.html
        
        // dirname - 提取到最后一个文件夹的全部路径
        console.log(path.dirname("http://134.23.43.55/a/b/c/d.html")); // http://134.23.43.55/a/b/c
        console.log(path.dirname("../a/b/c/d.html")); // ../a/b/c
        
        // extname -- 获取文件后缀
        console.log(path.extname('index.html')); // .html
        console.log(path.extname('index.coffee.md')); // .md
        console.log(path.extname("http://5.4.3.2/a/b/c/d.png")); // .png
        
        // join -- 智能拼接路径 (相对地址)
        console.log(path.join('./html', 'index.html')); // html\index.html
        console.log(path.join(__dirname, 'html', 'index.html'));
        // __dirname 获取的是当前文件所在文件夹的绝对地址
        
        // resolve -- 基于当前路径, 拼接路径(绝对地址)
        console.log(path.resolve('./html', 'index.html'));\html\index.html
        console.log(path.resolve(__dirname, 'html', 'index.html')); 

2.1 fs模块 - 异步读取文件

文件操作模块

  • 中文文档 - http://nodejs.cn/api/fs.html
  • 文件系统,对当前所在电脑的磁盘, 文件/文件夹的操作
const fs = require("fs"); // 引入内置的fs模块

console.log("文件开始");

// 异步读取文件
// 参数1: 文件路径
// 参数2: 读取所用编码(不设置读出来的是Buffer字节流, 文件本质上还是0和1的组成)
// 参数3: 回调函数 - 读取后无论成功与否都触发
fs.readFile("./html/index.html", "utf-8", (err, data) => {
    console.log(err);
    console.log("----");
    console.log(data);
})

console.log("nodejs执行完毕"); // 测试是否上面代码是异步

2.2 fs模块 - 判断读写是否成功

// 异步读取文件
// 参数1: 文件路径
// 参数2: 读取所用编码
// 参数3: 回调函数 - 读取后无论成功与否都触发
fs.readFile("./html/index.html", "utf-8", (err, data) => {
    if (err) { // 如果err有值, 证明报错
        console.log(err.message); // 打印错误信息(message属性固定名字)
    } else {
        console.log(data);
    }
})

2.3 fs模块 - 异步写入

文件无需提前创建

const fs = require("fs"); // 引入内置的fs模块

// 异步写入
// 参数1: 文件路径
// 参数2: 写入内容
// 参数3: 回调函数
fs.writeFile("./txt/1.txt", "我是插入的内容", (err) => {
    if (err) {
        console.log(err.message);
    } else {
        console.log("写入成功");
    }
})

2.4 fs模块 - 异步判断-同步写入

// 判断文件存在不
// 参数1: 文件路径
// 参数2: 回调函数
fs.access("./txt/1.txt", function(err){
    if (err) {
        console.log(err.message);
    } else {
        // 同步写入(带Sync就是同步方法, 无回调函数)
        // 参数1: 文件路径
        // 参数2: 写入内容
        fs.writeFileSync("./txt/1.txt", "同步写入的内容");
    }
})

总结: 所有方法如果带Sync结尾都是同步方法, 主线程在原地等待结果

2.5 案例 - 成绩管理文件

成绩.txt

小红=99 小白=100 小黄=70 小黑=66 小绿=88

利用fs模块和js代码, 把成绩.txt里的数据转换成如下格式

前端与移动开发----Node.js----node核心模块_第5张图片

const fs = require("fs");

fs.access("./txt/成绩.txt", function(err){
    if (!err) { // 如果无错误, 再读取这个文件
        fs.readFile("./txt/成绩.txt", "utf-8", function(err, data){
            // 把=换成: , 把空格换成\n
            let str = data.replace(/\s/g, "\n").replace(/=/g, ": ");
            // 写入到新的文件中
            fs.writeFile("./txt/成绩ok.txt", str, err => {
                if (err) console.log(err.message);
                else console.log("修改成功");
            })
        })
    }
})

2.6 尽量使用绝对地址

const fs = require("fs");
const path = require("path");
// 1. 知道什么是./ 什么是../
// .  当前文件所在文件夹   /代表开启文件夹访问下面的东西
// .. 代表返回上一级文件夹  /代表开启文件夹访问下面的东西

// 2. 为什么要使用绝对路径呢?
// 例如: 想给txt/1.txt写入内容 - 用相对路径
// fs.writeFile("./txt/1.txt", "写入内容", err => {
//     if (err) console.log(err.message);
//     else console.log("写入成功");
// })
// 实际运行, 以cmd中, node命令所在路径拼接这个相对路径

// 3. 解决方案
// nodejs有个内置的变量 __dirname 返回当前文件的文件夹的绝对路径
console.log(__dirname); 
fs.writeFile(path.join(__dirname, "./txt/1.txt"), "写入内容", err => {
    if (err) console.log(err.message);
    else console.log("写入成功");
})

2.7 querystring模块

查询字符串(id=1&name=zs&age=20)处理模块

const querystring = require("querystring"); // 引用内置核心模块 querystring

// 1. 模拟前台url形参过来的字符
let urlStr = "id=5&page=10&bookname=西游记";
// 2. 调用parse方法格式化成对象
let queryObj = querystring.parse(urlStr);
console.log(queryObj); //  { id: '5', page: '10', bookname: '西游记' }
console.log(queryObj.id);

// 总结: 可以用于解析key=value&key=value格式的字符串

3. http模块

上网, 客户端, 服务器

上网: 访问服务器, 获取和消费资源

客户端: 可以浏览和使用资源的终端设备, 例如电脑, 手机等

服务器: 用于提供资源的24开机, 性能和带宽要求很高的计算机 (无显示器)

服务器磁盘上的文件, 本身不能被直接访问, 需要通过web服务才可以把磁盘上的文件返回给客户端查看

HTTP模块

http模块 是 node 核心自带的, 用于搭建web服务功能 (服务就是一堆代码实现功能)

URL地址

url地址: 协议://域名或IP:端口号/文件夹路径/文件?参数

  • 127.0.0.1 是本机, localhost是本机域名 (固定)
  • 端口号, 确定计算机里的服务
    • 取值范围是:0-65535。 1023以下的端口已经分配给了常用的一些应用程序(尽量不要使用)

总结: 127.0.0.1(本机) -> 需要加上端口号(访问哪个功能) -> 路径和资源目标

终端里: ping 域名, 可以得到对应的地址

3.0 搭建Web服务器

  • 使用http模块搭建Web服务器

    创建 Web 服务器的步骤

    • 导入 http 核心模块
    • 创建 server 对象(server 对象负责建立连接,接收数据)
    • 注册 request 事件,当浏览器发送请求到服务器执行,设置处理请求的函数
    • 监听端口(这个步骤也可以放到注册request事件之前
    // 1. 引入 - 核心http模块 (核心内置 - node自带的)
    const http = require('http');
    
    // 2. 创建服务对象
    const server = http.createServer(); // create创建、server服务器
    
    // 3. 给server对象注册请求(request)事件,监听浏览器的请求。只要有浏览器的请求,就会触发该事件处理函数
    server.on('request', () => {
        console.log('我发现你的请求了,但是不想搭理你, 不响应返回任何结果');
    });
    
    // 4. 设置端口,开启服务, 成功触发一次函数体执行
    server.listen(3000, () => {
        console.log('服务器启动了');
    });
    
    // cmd终端 - 执行这个文件 (注意路径)
    // 现象: 发现光标一直在闪烁, 代表代码没执行完(如果有路径>就代表上一个命令执行完了, 等待你下一个命令输入)
    // 原因: 这是因为终端里正在有一个进程启动着呢(这是因为http会启动一个进程来监测别人的请求 - 相当于开机了一个服务器)
    // 注意: 如果终端关闭就相当于web服务关闭了
    
    
    // 用浏览器/能发起请求的工具 
    // 前台发起请求 ->  后台控制台打印但是并未作出响应, 所以前台转圈 等待后台的响应返回
    // 服务器的最终目的是要根据请求做出响应
    
    // ctrl+c 停止当前的进程
    

3.1 响应对象

当收到浏览器的请求后,会触发request事件的处理函数( request 和 response参数对象)

// 代码片段
server.on('request', function (req, res) {
  // 遇到前端发来的请求动作, 这个函数执行
})
  • 形参res

    • 响应对象,服务器给浏览器返回的响应内容,可以通过该对象设置
    • res.setHeader() 设置响应头,响应内容格式和编码
    • res.statusCode 设置状态码
    • res.end() 把响应报文(响应行、响应头、响应体)发送给浏览器
  • 响应代码

    • 响应一句话
    const http = require('http');
    const server = http.createServer();
    server.on('request', (req, res) => { // req(请求对象), res(响应对象)
        // 请求req: 前端发送过来的一切东西
        // 响应res: 服务器给浏览器返回的响应内容,可以通过该对象设置
    
        res.setHeader("Content-Type", "text/html; charset=utf-8;"); // 告诉前端, 我给你返回的内容是html文本, 编码格式是UTF-8请你这样去解析我给你返回的内容
        res.statusCode = 200; // 设置本次响应的状态码 (200 ok)
        res.end('响应的内容'); // 返回给前台响应内容, 并结束本次响应(一定要放在最下面)
    });
    
    server.listen(3000, () => {
        console.log('服务器启动了');
    });
    // 注意如果你当前3000的端口被使用, 再开启一个js作为服务器就会报错, 3000端口已经被占用
    

注意

  • 最后执行res.end() - 一次请求对应一次响应
  • res.end() 里只能响应字符串

3.2 请求对象_GET方式

server.on('request', function (req, res) {  
  // 形参req 是 请求request的意思,所有和请求相关的信息,都在req对象中
})
  • 形参req

    • 请求对象,浏览器发送的请求报文中的数据已经被解析到该对象上
    • req.url 获取请求行中的路径
    • req.method 获取请求行中的请求方法
    • req.headers 获取请求头数据
  • 代码实例

    const http = require('http');
    
    const server = http.createServer();
    
    server.on('request', (req, res) => { 
        console.log(req.method); // 获取前端使用的请求方式   GET
        console.log(req.url); // 获取前端使用的请求地址(从域名和端口往后的部分)   
        console.log(req.headers); // 获取前端使用的请求头  
        res.end(); 
    });
    
    server.listen(3000, () => {
        console.log('服务器启动了');
    });
    

3.3 请求对象-POST方式-接参数

const http = require('http');

const server = http.createServer();

server.on('request', (req, res) => {
    console.log(req.method); // POST
    console.log(req.url); 
    console.log(req.headers);

    // 接受参数
    let str = ''; // 定义一个用于保存数据的空字符串
    req.on('data', (chunk) => { // 给req注册data事件,只要有数据提交过来,就会触发;用于接收提交过来的数据(数据过大, 会多次触发, 接收字节)
        str += chunk; // 拼接到变量上
    });
    req.on('end', () => { // 给req注册end事件,当完全接收了提交过来的数据,就会触发
        console.log(str); 
    });
    res.end(str);
});
// 前端请求插件: 发送POST请求和参数 
server.listen(3000, () => {
    console.log('服务器启动了');
});

3.4 接口编写

需求: 后端监测前端发送的请求方式, 以及请求的url, 以及请求的参数

功能: GET /api/list 后台把数据返回给前端

功能: POST /api/add 前端把参数key=value&key=value字符串发到后台, 保存到数组里

const http = require('http');
const querystring = require("querystring");
const server = http.createServer();

let arr = []; // 不要写在下面的函数里, 不然每次请求都会初始化, 但是这个js重启代码会重新执行清空数组

server.on('request', (req, res) => {
    let { method, url } = req; // 提取请求方式, 和请求地址
    res.setHeader("Content-Type", "text/html; charset=utf-8;"); // 设置响应头, 返回的是中文

    // 1. GET方式 - 查询所有数据
    if (method == "GET" && url == "/api/list") {
        res.end(JSON.stringify({ // 把数据响应回给前端
            status: 200,
            msg: "获取成功",
            data: arr
        }));
    } else if (method == "POST" && url == "/api/add") { // 接收前端发来的数据, 组织格式保存到数组里
        // POST方式 - 添加数据到arr数组里 (要求前台传递一个JSON字符串数据)
        let str = '';
        req.on('data', (chunk) => {
            str += chunk;
        });
        req.on('end', () => {
            // 直接用queryString可以把key=value&key=value字符串转成对象格式
            let obj = querystring.parse(str.replace("?", ""));
            arr.push(obj); // 把发来的数据对象保存到全局 数组里
            res.end(JSON.stringify({
                status: 201,
                msg: "添加成功"
            }));
        });
    } else {
        res.end("请确认接口地址和对应的请求方式是否正确");
    }
});

server.listen(3000, () => {
    console.log('服务器启动了, http://127.0.0.1:3000');
});

4. 资源和接口服务器

网址 -> 服务器响应 -> 返回HTML等资源内容 (这也是上网的过程)

前端与移动开发----Node.js----node核心模块_第6张图片

网页访问过程:

注意: 浏览器上什么都没有, 都是通过网址来访问, 网址对应的服务器会返回内容给浏览器渲染展示

浏览器请求html / css文件 / js文件 / 图片文件 - 都是要从服务器上请求的

4.0 静态资源

// 本文件讲解, 浏览器请求url后, 服务器是如何把网页和静态资源返回给浏览器显示的
// 除了json字符串, html/css/js/图片都是资源, 也是由服务器返回给浏览器的 - 注意后端要设置响应头告诉浏览器返回数据的类型, 浏览器好解析
const fs = require('fs');
const http = require('http');

const server = http.createServer();

server.on('request', (req, res) => {
    // 1. req.method - 获取前端使用的请求方式
    // 2. req.url - 获取前端使用的请求地址(从域名和端口往后的部分)
    // 3. req.headers - 获取前端使用的请求头

    // url随便写(根据前端地址栏决定), 但是磁盘地址必须是相对/绝对路径
    if (req.url == "/clock/clock.html") {
        fs.readFile(__dirname + "/静态资源clock/clock.html", (err, data) => {
            res.setHeader("Content-Type", "text/html; charset=utf-8;");
            res.end(data);
        })
    } else if (req.url == "/clock/clock.css") {
        fs.readFile(__dirname + "/静态资源clock/clock.css", (err, data) => {
            res.setHeader("Content-Type", "text/css"); // 返回的是css代码
            res.end(data);
        })
    } else if (req.url == "/clock/clock.js") {
        fs.readFile(__dirname + "/静态资源clock/clock.js", (err, data) => {
            res.setHeader("Content-Type", "text/javascript"); // 返回的是js代码
            res.end(data);
        })
    } else if (req.url == "/clock/a.jpg") {
        fs.readFile(__dirname + "/静态资源clock/a.jpg", (err, data) => {
            res.setHeader("Content-Type", "image/jpeg"); // 返回的是图片数据
            res.end(data);
        })
    } else { // 如果上面都未匹配, 则这里执行
        res.statusCode = 404;
        res.statusMessage = "Not Found"
        res.end();
    }
});
server.listen(3000, () => {
    console.log('服务器启动了');
});

// 总结: 
// MIME类型, 就是后台返回内容, 设置的内容类型的固定字段
// 更多的MIME类型: https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types

4.1 完整服务器

一台服务器, 既能返回JSON字符串数据, 也能返回静态资源(html/css/js/图片) 给前端使用

const fs = require('fs');
const http = require('http');

const server = http.createServer();
server.on('request', (req, res) => {
    if (req.url == "/index.html") { // 此接口返回的是网页
        fs.readFile(__dirname + "/带Ajax请求的网页/index.html", (err, data) => {
            res.setHeader("Content-Type", "text/html; charset=utf-8;");
            res.end(data);
        })
    } else if (req.url == "/api/list") { // 此接口返回数据
        res.end(JSON.stringify({
            status: 200,
            msg: "获取成功",
            data: [{
                name: "小明",
                age: 39,
                sex: "男"
            }, {
                name: "小爱",
                age: 20,
                sex: "女"
            }]
        }));
    } else {
        res.statusCode = 404;
        res.statusMessage = "Not Found"
        res.end();
    }
});

server.listen(3000, () => {
    console.log('服务器启动了');
});

如有不足,请多指教,
未完待续,持续更新!
大家一起进步!

你可能感兴趣的:(前端与移动开发学习笔记,node.js,node.js,后端,前端)