文章目录
一、NodeJS 模块
1、模块概述
NodeJS 中每个.js 文件都是一个独立的模块,给.js 文件默认提供了一个名称为 module
的对象,用于指代当前 js 文件,可以通过 module 导出当前模块中的数据
NodeJS 中当模块开始使用时,会出现另一个概念:包
默认情况下 NodeJS 中模块和包都是同一个概念
- 模块当成一个独立的 js 文件
- 包当成存放多个模块的文件夹
2、系统模块
NodeJS 运行时安装好之后,默认提供的模块,如 fs 文件系统、net 网络模块、http 网
络处理模块等等;在项目应用中不需要安装可以直接使用的模块
// 引入系统模块
// 一个模块可以被多次引入,但是只会生效一次
// 第一次引入一个模块时,会将这个模块通过名称进行缓存
// 后面再次引入时根据名称进行判断是否已经已经引入
// 如果已经缓存了~说明已经引入了,直接从缓存提取
系统模块和自定义模块,引入顺序是什么样的呢?
默认情况下,应用中优先引入系统模块、然后引入加载自定义模块
- ① 引入的模块不带路径,默认引入系统模块/第三方模块
- ② 引入的模块带有相对路径,默认引入自定义模块
3、NodeJS 常见模块
系统模块:path,处理文件路径的模块
系统模块:url,处理和网址相关的数据
系统模块:querystring,第三方模块:qs
专门用于处理网址中的查询字符串【不完整的网址】
NodeJS 内建模块:http 模块!
/**
* http 模块
* 系统模块/内建模块
* 主要用于网络应用构建
*/
const http = require("http")
// 创建一个基本 WEB 服务器
const server = http.createServer((req, resp)=>{
resp.writeHead(200, {"Content-type": "text/html;charset=utf-8"})
resp.write("<h1>http://192.168.11.100:3000</h1>")
resp.write("hello NodeJS!你好 世界!hello WEB0608!")
resp.end()
})
// 启动服务器
server.listen(3000, "0.0.0.0", err=>{
console.log("WEB 服务已经启动")
})
二、NodeJS WEB
- 1、第一个 WEB 应用
创建一个 WEB 应用,新建一个应用文件夹:demo03WEB/
执行命令,初始化为 Node 应用 - cd demo03WEB/
- npm init
创建第一个应用模块:ex01 第一个 WEB.js
/**
* 第一个 WEB 的应用
*/
// 引入 http 模块,处理网络数据
const http = require("http")
// 创建一个服务器,可以接受和响应用户请求
const server = http.createServer(function(req, resp) {
// req: request 用户的请求对象
// resp: response 返回数据响应对象
// 给用户返回数据,设置响应头:返回 HTML 文本数据,使用 UTF-8 编码
resp.writeHead(200, {"Content-type": "text/html;charset=utf-8"})
// 编写返回给用户的数据
resp.write("<h1>hello 我的第一个 WEB 应用</h1>")
// 以固定的函数结尾,表示处理结束
resp.end()
})
// 监听 3000 端口,启动服务器
server.listen(3000, function(err) {
console.log("服务已经在 http://127.0.0.1:3000 启动")
})
启 动 上 述 代 码 , 打 开 浏 览 器 访 问 : http://localhost:3000 或 者
http://127.0.0.1:3000 都可以访问到服务器返回的页面
注意:停止该服务器,需要在控制台点击鼠标右键,选择 stop run code 才能停止正在
运行的 web 服务器;和普通程序运行之后直接结束的方式有区别!
构建的文件名称、文件夹名称其他的名称中尽量不要包含中文、空格
2、问题处理
开发项目过程中会出现各种问题,常见的问题的出现原因和解决方案如下
- ① 错误的文件名称
项目文件夹中创建了自己的js文件,文件名称
node.js
http.js
导致项目出现意料之外的错误!
这样的错误一般错误信息和真实错误内容对不上,只能依靠丰富的开发经验排查问题 - ② 拼写问题
开发过程中,部分单词容易拼写错误
正确:const http = require(“http”)
错误1:const http = requrie(“http”)
错误2:const http = require(“htpt”)
错误3:conts http = rquire(“http”) - ③ 项目启动报错
Error: listen EADDRINUSE: address already in use :::3000
错误:监听地址出现错误,地址对应的3000端口已经被占用!
-
查询系统中占用端口的进程编号
打开命令行,执行命令查询那个应用占用了3000端口
netstat -ano | findstr 3000 -
打开任务管理器,启动PID选项
-
根据查询到的进程编码,结束对应的程序
-
重新启动项目,就不会再出现端口被占用的情况
3、路径判断
一个成熟的项目一般会包含很多的功能,并不是通过一个唯一的url地址进行访问,如我们可以通过/login访问登录页面、/index访问主页、/register访问注册页面
关于用户请求地址:URL地址
完整地址:http://127.0.0.1:3000/index?name=“tom”
- http://协议
- 127.0.0.1 : ip地址
- port:端口
- /index:访问资源路径
- ?name=“tom”:参数数据
如果要通过不同的URL地址路径,访问不同的功能,需要改变上述地址中的资源路径
资源路径是用户请求的一部分,我们如果要获取并且判断资源资源,操作处理请求对象
需求:实现如下功能
http://localhost:3000/login 返回-会员登录页面
http://localhost:3000/register 返回-会员注册页面
http://localhost:3000/index 返回-系统首页页面
http://localhost:3000/profile 返回-用户中心
其他:返回404错误,没有路径
代码实现
/**
* 路径判断
* 用户访问不同的地址,返回不同的数据
*/
// 导入依赖的模块
const http = require("http")
// 创建一个服务器
const server = http.createServer((req, resp) => {
// 获取用户访问路径
let pathname = req.url
// 设置响应头
resp.writeHead(200, {"Content-type": "text/html;charset=utf-8;"})
// 判断用户访问路径
if(pathname.endsWith("favicon.ico")) {
resp.write("")
} else if(pathname.endsWith("login")) {
resp.write("<h2>会员-登录 页面</h2>")
}else if(pathname.endsWith("register")) {
resp.write("<h2>会员-注册 页面</h2>")
}else if(pathname.endsWith("index")) {
resp.write(`
<h2>系统 首页页面</h2>
<h4><a href="/login">登录</a></h4>
<h4><a href="/register">注册</a></h4>
`)
} else{
resp.write("<h3>404错误,没有这个路径</h3>")
}
resp.end()
})
// 启动服务器
server.listen(3000, err=> {
console.log("服务已经在http://localhost:3000启动")
关于项目中改动的问题
项目开发中,会频繁的修改源代码,原始的node启动模式每次修改后都需要重启程序才能让改动生效,严重降低了我们的开发效率
NodeJS社区提供了一个新的模块: nodemon,可以实现node命令的替换,以及程序中代码修改后的热加载(改动后立即生效)
// 全局安装nodemon
npm install nodemon -g
// 启动项目
// node demo01.js
nodemon demo01.js // 启动的项目热加载模式
4、访问网页
传统的项目中,用户发送一个URL地址,服务器会返回一个HTML网页给用户展示
结合http和fs完成网页数据的返回!
/**
* http服务器
* 响应网页数据
*/
// 引入http
const http = require("http")
const path = require("path")
const fs = require("fs")
// 创建服务器
const server = http.createServer((req, resp) => {
// 接受用户请求
let pathname = req.url
// 设置请求头
resp.writeHead(200, {"Content-type": "text/html;charset=utf-8"})
// 判断路径
if(pathname.endsWith("favicon.ico")) {
// 过滤一个无效的路径
resp.write("")
} else if(pathname.endsWith("index.html")) {
// 读取文件内容并返回
const content = fs.readFileSync(
path.join(__dirname, "html", "index.html"), "utf-8")
resp.write(content)
} else {
// 返回404错误,资源没有找到
resp.write("<h2>404 没有这个资源</h2>")
}
resp.end()
})
// 监听端口启动服务器
server.listen(3000, err=> {
console.log("服务已经在http://127.0.0.1:3000启动")
})
5、读取样式
一个完整的网页,不仅包含HTML文档,同时还会包含样式文件、JS脚本文件,这些文件内容的数量较多,无法一个一个读取,需要通过一些共同的读取文件内容的代码进行封装,完成任意文件的读取
/**
* 网页渲染升级
* 优化读取文件的过程
*/
// 引入模块
const http = require("http")
const path = require("path")
const fs = require("fs")
const url = require("url")
// 创建服务器
const server = http.createServer((req, resp) => {
// 获取用户访问路径,转换成URL对象
let pathname = req.url
let urlObj = url.parse(pathname)
pathname = urlObj.pathname.substr(1) // html/index.html
// 读取文件
fs.readFile(path.join(__dirname, pathname), (err, data) => {
// 判断用户访问路径后缀
if(pathname.endsWith(".html")) {
resp.writeHead(200, {"Content-type": "text/html;charset=utf-8"})
resp.write(data)
resp.end()
} else if(pathname.endsWith(".css")) {
resp.writeHead(200, {"Content-type": "text/css"})
resp.write(data)
resp.end()
} else if(pathname.endsWith(".js")) {
resp.writeHead(200, {"Content-type":
"application/x-javascript"})
resp.write(data)
resp.end()
}
})
})
// 启动服务器
server.listen(3000, err=> {
console.log("服务已经在http://localhost:3000启动了")
})
6、读取图片
代码实现:
/**
* 网页渲染升级
* 优化读取文件的过程
*/
// 引入模块
const http = require("http")
const path = require("path")
const fs = require("fs")
const url = require("url")
// 创建服务器
const server = http.createServer((req, resp) => {
// 获取用户访问路径,转换成URL对象
// console.log(req)
let pathname = req.url
let urlObj = url.parse(pathname)
pathname = urlObj.pathname.substr(1)
if (pathname.endsWith(".webp")) {
resp.writeHead(200, { "Content-type": "image/webp" })
const stream = fs.createReadStream(path.join(__dirname, pathname))
const respData = []
if(stream) {
// 以缓冲的方式读取图片数据,追加到数组中
stream.on("data", chunk=> respData.push(chunk))
stream.on("end", () => {
// 将数组中的数据转换成缓冲数据
const finalData = Buffer.concat(respData)
// 响应数据
resp.write(finalData)
resp.end()
})
}
} else {
// 读取文件
fs.readFile(path.join(__dirname, pathname), (err, data) => {
// 判断用户访问路径后缀
if (pathname.endsWith(".html")) {
resp.writeHead(200, { "Content-type": "text/html;charset=utf-8" })
resp.write(data)
resp.end()
} else if (pathname.endsWith(".css")) {
resp.writeHead(200, { "Content-type": "text/css" })
resp.write(data)
resp.end()
} else if (pathname.endsWith(".js")) {
resp.writeHead(200, { "Content-type": "application/x-javascript" })
resp.write(data)
resp.end()
}
})
}
})
// 启动服务器
server.listen(3000, err => {
console.log("服务已经在http://localhost:3000启动了")
})