之前js主要就是在浏览器中进行dom编程


一、node简介
1、什么是node.js
1、Node.js是一个基于chorme v8引擎的javascript运行时
2、特点:单线程、事件驱动、异步I/O、轻量级
相当于餐厅只有一个服务员,但是这个服务员非常厉害,不怕I/O读写,但是比较怕请求里面有业务逻辑计算,这样就无法相应其他请求
3、Node.js是目前最大的开原生态系统之一。NPM(node package management)
2、环境变量
环境变量path,由多个路径组成,每个路径之间用;间隔
执行指令时,会按照path中指定的路径,逐一查找直到最后
二、基本使用
1、案例一
js文件可以直接运行,只需要在终端中进入相应路径,输入node 文件名.js
dom和bom的东西无法使用
let add = (a,b)=>a+b
console.log(add(1,2)) // 3
js模块化规范
- commonJS规范,node里面使用的规范 ,使用require引入模块
- AMD规范
- CMD规范
- ES6模块化,使用import和export(导入和导出)
2、案例二
fs.readFile(path[,options],callback) 异步操作 fs.readFileSync(path[,options],callback) 同步操作
var fs = require("fs") //引入模块fs
//读取文件
fs.readFile("./res/test.txt",(err,data)=>{
if(!err){
console.log(data.toString())
}
})//后面是回调函数
console.log("end") //先打印出end再打印出文件中的内容,因为这是异步操作,可以先打印出end再调用回调函数
同步操作没有回调函数
var fs = require("fs") //引入模块fs
//读取文件
var data = fs.readFileSync("./res/test.txt")
console.log("data")
console.log("end")//先打印出文件内容,再打印出end,因为这是同步操作,所以这个方法一般不用
3、案例三
创建一个web服务
var http = require("http")
var server = http.createServer((req,res)=>{
res.end("<h1>hello,Node.js</h1>") //通过end方法将响应的内容写到响应对象中
})
//监听一个端口,回调函数是当端口连接上时要进行的操作
server.listen(3000,()=>{
console.log("server start.port:3000")
})
request headers中的内容
accept:能接受的内容
accept-encoding:能接受的编码
response headers
里面要说清楚返回的内容是什么,编码是什么,不然浏览器会出现乱码
var http = require("http")
var server = http.createServer((req,res)=>{
res.setHeader("Content-Type","text/html;charset=utf-8")
res.end("<h1>哈喽,Node.js</h1>") //这样中文就会正确解析出来
})
server.listen(3000,()=>{
console.log("server start.port:3000")
})
三、模块化
1、概述
代码模块化的优点
- 便于代码的重用
- 便于代码的维护
- 提高代码的可读性
问题
- 如何去定义一个模块
- 如何使用模块
- 模块间的关系如何处理
为了解决这些问题就要设置标准,下面这四种标准
ConmmonJS(主要介绍这个标准)
ES6
AMD
CMD
2、模块的定义和使用
node中,一个js文件就是一个模块
每个js文件中的代码都是独立运行在一个函数中的,而不是在一个全局作用域中,所以说一个模块中的变量和函数其他模块无法直接访问
通过exports来向外暴露变量和方法
ModuleA.js
var x = "ModuleA x"
var y = "ModuleA y"
function fun(){
console.log("ModuleA fun is called")
}
exports.xx = x;
exports.yy = y;
exports.fun = fun;
通过require函数引入外部的模块,自定义的模块需要传入路径,前提是要引入的模块可以被引用 ModuleB.js
var moduleA = require("./ModuleA")
console.log(moduleA.xx)
console.log(moduleA.yy)
模块分为两大类
核心模块
由CommonJS提供 核心模块的标识就是模块的名字
文件模块
由用户自己创建的模块 文件模块的标识就是文件的路径
3、全局对象
在node中有一个全局对象 global,作用类似浏览器中的window
在全局中创建的变量都会作为global的属性保存
ModuleC
//这里的a是局部变量,因为之前提到过,模块相当于一个函数
var a = 100
//b是全局变量
b = 100
console.log(global.b) //100
fun = function(){
console.log("ModuleC fun is called")
}
ModuleD
var moduleC = require("./ModuleC")
console.log(global.b) //100
global.fun
4、模块中的参数
node中,一个js文件就是一个模块
每个js文件中的代码都是独立运行在一个函数中的
在node执行模块中代码时,它会首先在代码的最顶部,添加如下代码
function(exports,require,module,_filename,_dirname){
内部是我们自己编写的代码
在代码的最底部添加如下代码
}
exports
使用该对象将变量和函数进行暴露
require
使用该对象引入其他模块
module
代表当前模块本身
exports就是module的属性
暴露既可以使用exports,也可以使用module.exportsfilename
当前模块的完整路径
dirname
当前模块所在文件夹的完整路径
var x = "ModuleA x"
var y = "ModuleA y"
function fun(){
console.log("ModuleA fun is called")
}
console.log(arguments) //函数接收的参数列表,能打印出这个说明上面的代码就是运行在一个函数中的
console.log(arguments.callee + "") //这个是arguments的一个属性,但是不推荐使用,es6中已经不推荐使用arguments了,而是推荐使用...
5、exports和module.exports
require方能看到的只有module.exports这个对象,它看不到exports对象,而我们在编写模块的时候用到的exports对象实际上只是对module.exports的引用
www.zhihu.com/question/26…
使用exports的代码
Module1.js
var x = "Module1 x"
var y = "Module1 y"
function fun(){
console.log("Module1 fun is called")
}
exports.x = x
exports.y = y
exports.fun = fun
Module2.js
var module1 = require(./Module1)
console.log(module1.x)
console.log(module1.y)
module1.fun()
使用module.exports的代码
var x = "Module1 x"
var y = "Module1 y"
function fun(){
console.log("Module1 fun is called")
}
module.exports.x = x
module.exports.y = y
module.exports.fun = fun
//或者下面这个写法
module.exports = {
x, //属性简写
y,
fun
}
exports = {//不能这样写,会报错
x,y,fun
}
console.log(module.exports) //{x:'Module1 x',y:'Module1 y',fun:[Function:fun]}
console.log(module.exports=== exports)//false
四、包管理
1、包
将一组组相关的模块组合在一起,形成一个完整独立的功能模块,例如http、fs
包规范由包结构和包描述文件
包中的各种文件
-package.json 包的描述文件
-bin 可执行的二进制文件
-lib js代码
-doc 文档
-test 单元测试
包的描述文件
描述包的相关信息,供外部古曲分析
2、包的描述文件
package.json
name: 模块的名称
version:模块的版本
author: 模块的作者
description:模块的描述
keywords:模块的关键字
contributors:项目的贡献者
homepage:项目主页
repository:项目仓库
dependencies:生产环境下项目的依赖
devdDependencies:开发环境下项目的依赖(开发过程中使用到的工具模块babel、webpack)
scripts: 执行npm脚本命令的简写
3、npm
npm:node package management
node使用npm帮助其完成第三方模块的发布、安装和依赖等
npm init
npm init -y 包初始化npm install 包名
npm install 包名--save
npm install 包名 --save-dev 下载到开发环境下的依赖中
npm install 包名--global 全局安装,不推荐这种方式
npm remove 包名
正常情况下,npm是从国外的仓库下载,速度可能会比较满,这时候可以用淘宝镜像下载,这时候就要用 cnpm, 也可以使用yarn
五、构建web应用
1、路由
req.url
页面上所有的静态资源都需要在请求中来获取
var http = require("http")
var server = http.createServer((req,res)=>{
res.setHeader("Content-Type","text/html;charset=utf-8")
if(req.url == "/favicon.ico"){
return
}else if(req.url == "/"){
res.end("<h1>首页</h1>")
}else if(req.url == "/music.html"){
res.end("<h1>音乐频道</h1>")
}else if(req.url == "/news.html"){
res.end("<h1>新闻频道</h1>")
}else {
res.end("<h1>访问的资源不存在</h1>")
}
})
server.listen(3000,()=>{
console.log("server start.port:3000")
})
以前使用url伪静态技术
利用相关工具将地址"/emp.jsp?id=001"转化为"/emp/001"
现在使用node就不需要考虑这种问题
下面的正则表达式意思为
以emp开头 ^/emp 后面跟着6位数字 /[\d]{6}$
if(/^\/emp\/[\d]{6}$/.test(req.url)){
var reg = /^\/emp\/([\d]{6})$/ //将[\d]{6}括了起来,将其变为子正则表达式
//reg.exec(req.url)会将整个正则表达式以及子表达式的匹配结果返回,包括编号,位置下标
var bianhao = reg.exec(req.url)[1]
res.end("<h1>员工信息:编号"+bianhao + "</h1>")
}
练习
从json文件中读取数据,根据编号匹配显示到屏幕上
var http = require("http")
var fs = require("fs")
var server = http.createServer((req,res)=>{
res.setHeader("Content-Type","text/html;charset=utf-8")
if(req.url == "/favicon.ico"){
return
}else if(req.url == "/"){
res.end("<h1>首页</h1>")
}else if(req.url == "/music.html"){
res.end("<h1>音乐频道</h1>")
}else if(req.url == "/news.html"){
res.end("<h1>新闻频道</h1>")
} else if (/^\/emp\/[\d]{6}$/.test(req.url)) {
var reg = /^\/emp\/([\d]{6})$/
var bianhao = reg.exec(req.url)[1]
fs.readFile("./emps.json",(err,data)=>{
if(err){
console.log("文件读取失败")
return
}
var dataObj = JSON.parse(data.toString())
if(dataObj.hasOwnProperty(bianhao)){
res.write("<h1>员工信息 编号:" + bianhao+ "</h1>")
res.write("<h2>姓名:" + dataObj[bianhao]["name"] + "</h2>")
res.write("<h2>部门:" + dataObj[bianhao]["dept"] + "</h2>")
res.write("<h2>工资:" + dataObj[bianhao]["sal"] + "</h2>")
res.end("")
}else{
res.end("<h1>编号:"+bianhao+"的员工不存在</h1>")
}
})
}
else {
res.end("<h1>访问的资源不存在</h1>")
}
})
server.listen(3000,()=>{
console.log("server start.port:3000")
})
jsp、php、aspx 通过代码引擎 动态生成 html
2、静态资源文件的访问
上面使用res.end的写法比较麻烦,与servelt类似。将静态页面的代码嵌入了代码中,这样子看起来非常复杂
所以可以将静态页面单独写到一个html中,再进行读取
下面代码是对静态页面、图片的访问

var http = require("http")
var fs = require("fs")
var server = http.createServer((req,res)=>{
res.setHeader("Content-Type","text/html;charset=utf-8")
if(req.url == "/favicon.ico"){
return
}else if(req.url == "/"){
fs.readFile("./public/index.html",(err,data)=>{
res.end(data)
})
}else if(req.url == "/timg.jpg"){
fs.readFile("./public/timg.jpg",(err,data)=>{
res.setHeader("Content-Type","image/jpg") /*这里是图片,所以需要重新设置响应头*/
res.end(data) /* data是二进制的字节数据*/
})
}else if(req.url == "/style.css"){
fs.readFile("./public/style.css",(err,data)=>{
res.setHeader("Content-Type","text/css") /*这里是css,所以需要重新设置响应头*/
res.end(data)
})
}else if(req.url == "/script.js"){
fs.readFile("./public/script.js",(err,data)=>{
res.setHeader("Content-Type","application/x-javascript") /*这里是js,所以需要重新设置响应头*/
res.end(data)
})
}else {
res.end("<h1>访问的资源不存在</h1>")
}
})
server.listen(3000,()=>{
console.log("server start.port:3000")
})
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="style.css">
<script type="text/javascript" src="script.js"></script>
</head>
<body>
<h1>首页</h1>
<img src="timg.jpg" alt="">
</body>
</html>
script.js
alert("hello");
style.css
h1{
color: blue;
}
3、相关模块
url
localhost:3000/emp/1002
这个请求中url为 /emp/1002
console.log(req.url)
var urljson = url.parse(req.url) //将一个URL字符串转换成对象并返回。
console.log("urljson", urljson)
var pathname = urljson.pathname
console.log("pathname", pathname)

pathname
/emp/1002
path
path中的属性
路径:localhost:3000/emp.jsp?id=1001&pwd=10
extname
path的后缀名,可以根据它设置响应头
var extname = path.extname(pathname)
console.log("extname", extname) //jsp
querystring
querystring 模块提供用于解析和格式化 URL 查询字符串的实用工具。
var query = urljson.query
console.log("query", query) //id=1001&pwd-10
var queryjson = querystring.parse(query) //将字符串解析为一个对象,再通过对象属性进行访问
console.log("queryjson",queryjson.id, queryjson.pwd) //1001 10
4、模拟apache
如果网址里输入localhost:3000/xx,让它直接跳转到xx里面的index.html页面
解决方案一
在pathname后面添加"/index.html"
if(!extname){ /*如果没有后缀名,则跳转到index.html文件*/
if(pathname.substr(-1) != "/"){
pathname += "/index.html"
}else{
pathname += "index.html"
}
}
解决方案二:使用重定向
响应码 302:重定向,当响应码为302时,表示服务器要求浏览器重新再发一个请求,服务器会发送一个响应头Location,它指定了新请求的URL地址
if(!extname){
if(pathname.substr(-1) != "/"){
res.writeHead(302,{"Location":pathname + "index.html"})
}else{
res.writeHead(302,{"Location":pathname + "index.html"})
}
res.end("")
return
}
六、experss框架
基于 Node.js 平台,快速、开放、极简的 Web 开发框架
1、介绍
node使用http模块构建web应用的缺点
路由不方便,甚至需要用正则表达式来匹配
静态资源服务使用不方便
页面呈现不方便,没有模板引擎的使用
2、基本使用
var express = require("express")
var app = express()
app.get("/",function(req,res){
res.send("<h1>首页</h1>") /*res.end只能支持两种参数,要么字符串,要么Buffer
res.send可以支持多种参数,比如可以传json对象,Buffer,String,Array */
})
app.get("/music",function(req,res){
res.send("<h1>音乐频道</h1>")
})
app.get("/news",function(req,res){
res.send("<h1>新闻频道</h1>")
})
app.get("/emp/:empno",function(req,res){
res.send("<h1>员工信息 编号:" + req.params.empno+"</h1>")
})
app.listen(3000,()=>{
console.log("服务已启动,端口号3000")
})
添加静态文件
这样就能访问静态化的文件
app.use(express.static("public")) /*将要静态化的文件夹写进去*/
__dirname
app.get("/",function(req,res){
console.log("__dirname",__dirname) //打印出文件夹完整路径
console.log(path.join(__dirname,"public")) //在路径最后添加一个“public”
res.send("<h1>首页</h1>")
})
app.use("/static",express.static(path.join(__dirname,"public"))) //通过/static/index.html访问public文件夹的index.html
//即添加了一个虚拟路径