文章目录
1.概念
- URL(统一资源定位符)
URL的组成:传输协议://服务器IP或域名:端口/资源所在位置标识 - 开发过程中客户端和服务器端说明
- 开发阶段,客户端和服务器端使用同一台电脑(客户端:浏览器;服务器端:Node) 连接:本地服务器,域名:localhost ;IP:127.0.0.1
- 客户端:在浏览器中运行的部分,就是用户看到并与之交互的界面程序,使用HTML、css、JavaScript构建
- 服务器端:在服务器中运行的部分,负责存储数据和处理应用逻辑
2.创建web服务器
3.获取报文
4.响应报文
5.请求参数
GET请求参数
参数被放置在浏览器地址栏中:http://localhost:3000<font color="red">?name=falcon&age=20</font>
// 引入url,用于处理url地址
const url = require('url')
// 获取请求地址
// console.log(req.url);
// 第一个参数:要解析的url地址;第二个参数(true):将查询参数解析成对象形式
// console.log(url.parse(req.url,true).query);
// let params = url.parse(req.url,true).query
// console.log(params.name);
// console.log(params.age);
// 参数解构
let { query,pathname } = url.parse(req.url,true)
console.log(query.name);
console.log(query.age);
if(pathname == '/index' || pathname == '/'){
// res.end('<h2>index page</h2>')
res.end('<h2>欢迎来到首页</h2>')
}else if(pathname == '/list'){
res.end('list page')
}else{
res.end('not found')
}
POST请求参数
参数被放置在请求体中进行传输;获取post参数需要用到data事件和end事件;使用querystring模块将参数转换为对象格式
//post.js
// 引入http模块
const http = require('http')
// 创建网站服务器
const app = http.createServer()
// 引入querystring,能把字符串转换为对象格式
const querystring = require('querystring')
// 客户端发送请求
app.on('request',(req,res)=>{
// post参数是通过事件的方式接受的:data(请求参数传递时) 和 end(请求参数传递完成时)
let postParams = '';
req.on('data', params => {
postParams += params
})
req.on('end',()=>{
// console.log(postParams);
postParams = querystring.parse(postParams)
console.log(postParams);
})
res.end('ok')
})
// 监听一个端口
app.listen(3000)
console.log('服务器启动成功!');
<!-- form.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>
</head>
<body>
<!-- method 指定当前表单的提交方式;action 指定当前表单的提交地址 -->
<form action="http://localhost:3000" method="POST">
<input type="text" name="username" id="">
<input type="password" name="password" id="">
<input type="submit" value="提交">
</form>
</body>
</html>
6.路由
//route/app.js
// 引入http模块
const http = require('http')
// 引入url
const url = require('url')
// 创建网站服务器
const app = http.createServer()
// 客户端发送请求
app.on('request',(req,res)=>{
// 获取客户端请求方式
const method = req.method.toLowerCase()
// 获取客户端请求地址
const pathname = url.parse(req.url).pathname
// 对响应报文的处理
res.writeHead(200,{
'content-type':'text/html;charset=utf8'
})
if(method == 'get'){
if(pathname == '/' || pathname == '/index'){
res.end('欢迎来到首页');
}else if(pathname == '/list'){
res.end('list page')
}else{
res.end('not found')
}
}else if(method == 'post'){
}
// res.end('ok')
})
// 监听一个端口
app.listen(3000)
console.log('服务器启动成功!');
7.静态资源和动态资源
静态资源:服务器不需要处理,可以直接响应给客户端的资源为静态资源
动态资源:相同的请求地址不同的响应资源
//静态资源实例
// 引入http
const http = require('http')
// 引入url模块,用于处理URL地址
const url = require('url')
// 引入path模块,用于获取文件的绝对路径
const path = require('path')
// 引入fs模块,读取文件
const fs = require('fs')
// 引入mime,能根据当前请求的路径,分析出资源的类型,并将资源类型通过返回值的方式返回
const mime = require('mime')
// 创建web服务器
const app = http.createServer()
// 客户端发送请求
app.on('request',(req,res) => {
// 获取用户的请求路径
let pathname = url.parse(req.url).pathname
pathname = pathname == '/' ? '/default.html' : pathname
// 将用户的请求路径转换为服务器实际的硬盘路径
// res.end(path.join(__dirname,'public' + pathname))
let realPath = path.join(__dirname,'public' + pathname)
// 获取资源的类型
// console.log(mime.getType(realPath));
let type = mime.getType(realPath)
// 文件读取成功,error为null,result为读取的内容;读取失败,error为失败的信息内容,result为null
fs.readFile(realPath,(error,result) => {
// 错误处理
if(error != null){
res.writeHead(404,{
'content-type':'text/html;charset=utf8'
})
res.end('文件读取失败!')
return
}
// 读取正确
res.writeHead(200,{
'content-type':type
})
res.end(result)
})
})
// 监听一个端口
app.listen(3000)
console.log('服务器启动成功');
8.同步API和异步API
同步API
只有当前API执行完成后,才能执行下一个API
console.log('before');
setTimeout(function(){
console.log('last');
},2000)
console.log('after');
异步API
当前API的执行不会阻塞后续代码的执行
区别
- 同步API可以从返回值中拿到API执行结果,异步API不可以
- 同步API代码的执行顺序会从上到下依次执行,前面代码会阻塞后面代码的执行;异步API不会等API执行完成后再向下执行代码
回调函数
自己定义函数让别人去调用
回调地狱
// 引入fs模块
const fs = require('fs')
// 多层的循环嵌套
fs.readFile('./1.txt','utf8',(err,result1) => {
console.log(result1);
fs.readFile('./2.txt','utf8',(err,result2) => {
console.log(result2);
fs.readFile('./3.txt','utf8',(err,result3) => {
console.log(result3);
})
})
})
回调地狱的解决(Promise)
Promise解决Node.js异步编程中回调地狱的问题
// 引入fs模块
const { rejects } = require('assert');
const fs = require('fs');
const { resolve } = require('path');
// 解决回调地狱问题
function p1(){
return new Promise((resolve,reject) => {
fs.readFile('./1.txt','utf8',(err,result1) => {
resolve(result1)
})
})
}
function p2(){
return new Promise((resolve,reject) => {
fs.readFile('./2.txt','utf8',(err,result2) => {
resolve(result2)
})
})
}
function p3(){
return new Promise((resolve,reject) => {
fs.readFile('./3.txt','utf8',(err,result3) => {
resolve(result3)
})
})
}
// 没有嵌套,解决了回调地狱的问题
p1().then((r1) => {
console.log(r1);
return p2()
})
.then((r2) => {
console.log(r2);
return p3()
})
.then((r3) => {
console.log(r3);
})
异步函数
可以将异步代码写成同步的形式,让代码不再有回调函数的嵌套,使代码变得清晰明了
//异步函数基础语法
// 1.在普通函数前面加async,普通函数变异步函数
// 2.异步函数默认返回值是promise对象
// 3.在异步函数内部使用throw关键字进行错误抛出
/**
* await关键字
* 1.它只能出现在异步函数中
* 2.await promise 它可以暂停异步函数的执行,等待promise对象返回结果后再向下执行
*/
async function fn(){
// throw之后的代码不在执行
throw '发生错误';
return 123
}
// console.log(fn());
fn().then((data) => {
console.log(data);
}).catch((err) => {
console.log(err);
})
async function p1(){
return 'p1'
}
async function p2(){
return 'p2'
}
async function p3(){
return 'p3'
}
async function run(){
let r1 = await p1()
let r2 = await p2()
let r3 = await p3()
console.log(r1);
console.log(r2);
console.log(r3);
}
run()
// 导入fs模块
const fs = require('fs')
// 引入promisify方法.用来改造现有异步函数的api,让其返回promise对象,从而支持异步函数语法
const promisify = require('util').promisify
// 此时readFile的读取结果就是一个promise对象
const readFile = promisify(fs.readFile)
async function run(){
let r1 = await readFile('./1.txt','utf8')
let r2 = await readFile('./2.txt','utf8')
let r3 = await readFile('./3.txt','utf8')
console.log(r1);
console.log(r2);
console.log(r3);
}
run()
9.Node全局对象global
浏览器中全局对象是window,node中全局对象是global
// 与不带global结果相同
globalThis.console.log('global下的log方法')
globalThis.setTimeout(function(){
console.log('123');
},2000)
10.数据库(MongoDB)
使用数据库的原因:
MongoDB可视化软件:MongoDB Compass
mongoose第三方包
关于数据库的所有操作都是异步操作
- 使用node.js操作MongoDB数据库需要依赖node.js第三方包mongoose
下载
npm install mongoose
启动
命令行工具中停止mongodb:net stop mongoDB
;启动mongodb:net start mongoDB
连接
创建数据库
MongoDB中不需要显示创建数据库,如果正在使用的数据库不存在,MongoDB会自动创建
MongoDB的增删改查
创建集合
分为两步,对集合设定规则;创建集合(大写,生成后的数据库是小写形式并加s)
创建文档(向集合中插入数据)
分为两步:创建实例集合;调用实例对象下的save方法将数据保存到数据库中
create方法也返回promise对象
// 引入操作MongoDB的第三方包mongoose
const mongoose = require('mongoose')
// 建立数据库的连接
mongoose.connect('mongodb://localhost/dbDemo',{
useNewUrlParser: true,
useUnifiedTopology: true
})
.then(() => console.log('数据库连接成功!'))
.catch(err => console.log(err,'数据库连接失败!'))
// 创建集合规则
const courseSchema = new mongoose.Schema({
name:String,
author:String,
isPublished:Boolean
})
// 使用规则创建集合:两个参数,集合名称,创建集合规则
const Course = mongoose.model('Course',courseSchema) //courses
// // 方法一:创建集合构造函数实例
// const course = new Course({
// name:'node.js基础',
// author:'falcon讲师',
// isPublished:true
// })
// // 将数据保存到数据库中
// course.save()
// // 方法二:创建集合构造函数实例
// Course.create({name:'JavaScript',author:'alice',isPublished:false},(err,result) => {
// console.log(err);
// console.log(result);
// })
// 方法三:创建集合构造函数实例
Course.create({name:'html',author:'lily',isPublished:false})
.then(res => console.log(res))
.catch(err => console.log(err))
向MongoDB数据库中导入数据
准备:找到MongoDB的安装目录,将安装目录下的bin目录放置在环境变量中
mongoimport -d 数据库名 -c 集合名称 --file/--jsonArray 要导入的数据文件
查询文档
删除文档
更新文档
// 引入操作MongoDB的第三方包mongoose
const { countReset } = require('console')
const mongoose = require('mongoose')
// 建立数据库的连接
mongoose.connect('mongodb://localhost/dbDemo',{
useNewUrlParser: true,
useUnifiedTopology: true
})
.then(() => console.log('数据库连接成功!'))
.catch(err => console.log(err,'数据库连接失败!'))
// 创建集合规则
const userSchema = new mongoose.Schema({
name:String,
age:Number,
hobbies:[String]
})
// 使用规则创建集合:两个参数,集合名称,创建集合规则
const User = mongoose.model('User',userSchema) //users
// find()方法查询返回的结果都是数组
// // 查询用户集合中的所有文档
// User.find().then(result => console.log(result))
// // 查询name="falcon"的用户信息
// User.find({name:'falcon'}).then(result => console.log(result))
// findOne 返回一条文档,返回一个对象
// // 默认返回当前集合中的第一条数据
// User.findOne().then(result => console.log(result))
// // 查找age=18的数据对象
// User.findOne({age:18}).then(result => console.log(result))
// // 条件查询:大于、小于
// User.find({age:{$gt:16,$lt:20}}).then(result => console.log(result))
// // 查询包含
// User.find({hobbies:{$in:['singing']}}).then(result => console.log(result))
// // 选择要查询的字段
// User.find().select('name hobbies').then(result => console.log(result))
// // 除去默认带的id属性
// User.find().select('name hobbies -_id').then(result => console.log(result))
// // 按照年龄进行排序(默认为升序)
// User.find().sort('age').then(result => console.log(result))
// // 按照年龄降序进行排序
// User.find().sort('-age').then(result => console.log(result))
// // skip跳过多少条数据 limit限制查询数据(意思是略过第一条,连续查询两条)
// User.find().skip(1).limit(2).then(result => console.log(result))
// // 查找到一条文档并删除,返回删除文档。 删除name=falcon的文档
// Course.findOneAndDelete({}).then(result => console.log(result))
// // 删除多条数据。如果条件为空,则所有的数据都要删除
// // 返回结果: { n: 1, ok: 1, deletedCount: 1 }
// User.deleteMany({age:16}).then(result => console.log(result))
// 更改单个文档,返回一个promise对象。返回结果:{ n: 1, nModified: 1, ok: 1 }
// User.updateOne({name:'falcon'},{name:'Eileen'}).then(result => console.log(result))
// User.updateOne({name:'alice'}).then(result => console.log(result))
// 更新多个文档,第一个为查询条件,不传对象或者传空值,默认更改所有的,返回一个promise对象。返回结果:{ n: 3, nModified: 1, ok: 1 }
User.updateMany({name:'Eileen'},{name:'rose'}).then(result => console.log(result))
mongoose验证
// 引入操作MongoDB的第三方包mongoose
const mongoose = require('mongoose')
// 建立数据库的连接
mongoose.connect('mongodb://localhost/dbDemo',{
useNewUrlParser: true,
useUnifiedTopology: true
})
.then(() => console.log('数据库连接成功!'))
.catch(err => console.log(err,'数据库连接失败!'))
// 创建集合规则
const postSchema = new mongoose.Schema({
title:{
type:String,
// required:true
required:[true,'请传输标题信息'],
minlength:[2,'长度不得少于两位'],
maxlength:[5,'长度不能超过五位'],
// trim 去除首尾的空格
trim:true
},
age:{
type:Number,
min:[16,'年龄不得小于16岁'],
max:[80,'年龄不得大于80岁']
},
publishDate:{
type:Date,
default:Date.now
},
category:{
type:String,
// 枚举 列举出当前字段可以赋值的范围
// enum:['html','css','javascript','node.js']
enum:{
values:['html','css','javascript','node.js'],
message:'分类名称要在指定范围内'
}
},
author:{
type:String,
validate:{
validator:v =>{
// 返回一个布尔值,true,验证成功;false,验证失败。v要验证的值
return v && v.length > 4
},
// 自定义错误信息
message:'传入的值不符合验证规则'
}
}
})
// 创建集合
const Post = mongoose.model('Post',postSchema) //posts
// 向当前集合中插入数据
// Post.create({title:' aa '}).then(result => console.log(result)) //{ _id: 5f8e3682d7fe2d42bcbe34a2, title: 'aa', __v: 0 }
// Post.create({title:' a a '}).then(result => console.log(result)) //{ _id: 5f8e3699463f101dac905728, title: 'a a', __v: 0 }
Post.create({title:'cc',age:13,category:'java',author:'a'})
.then(result => console.log(result))
.catch(error => {
// 获取错误信息对象
const err = error.errors
// 循环错误信息对象
for(var attr in err){
console.log(err[attr]['message']);
}
})
// 删除
// Post.deleteMany({}).then(result => console.log(result))
集合关联
// 引入操作MongoDB的第三方包mongoose
const mongoose = require('mongoose')
const { title } = require('process')
// 建立数据库的连接
mongoose.connect('mongodb://localhost/dbDemo',{
useNewUrlParser: true,
useUnifiedTopology: true
})
.then(() => console.log('数据库连接成功!'))
.catch(err => console.log(err,'数据库连接失败!'))
// 用户集合规则
const userSchema = new mongoose.Schema({
name:{
type:String,
required:true
}
})
// 文章集合规则
const postSchema = new mongoose.Schema({
title:{
type:String
},
// *1.将文章集合和用户集合关联
author:{
type:mongoose.Schema.Types.ObjectId,
ref:'User'
}
})
// 创建用户集合
const User = mongoose.model('User',userSchema) //users
// 创建文章集合
const Post = mongoose.model('Post',postSchema) //posts
// 创建用户
// User.create({name:'falcon'}).then(result => console.log(result))
// 创建文章
// Post.create({title:'123',author:'5f8e417419d60e49b01044da'}).then(result => console.log(result))
// *2.查询发布文章的author信息
Post.find().populate('author').then(result => console.log(result))
11.模板引擎
第三方模块,让开发者以更加友好的方式拼接字符串,使代码更清晰和易于维护
art-template
- 命令行中使用
npm install art-template
安装 - 使用
const template = require('art-template')
引入模块引擎 - 告诉模板引擎要拼接的数据和模板:
const html = template('模板路径',数据)
//app.js
// 导入模板引擎
const template = require('art-template')
// 引入path模块
const path = require('path')
// 模板路径要用绝对路径
const views = path.join(__dirname,'views','index.art')
const html = template(views,{
name:'falcon',
age:20
})
console.log(html);
<!-- index.art -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
{{name}}
{{age}}
</body>
</html>
运行app.js后的结果:
语法
标准语法
- 输出
{{ 数据 }}
- 原文输出
{{ @数据 }}
- 条件判断:
{{if 条件}} ... {{/if}}
{{if v1}} ... {{else if v2}} ... {{/if}}
- 循环:
{{each target}} {{$index}} {{$value}} {{/each}}
- 子模板:使用子模板可将网站公共区块(头部、底部)抽离到单独的文件中
{{include '模板(路径)'}}
- 模板继承:使用模板继承可以将网站HTML骨架抽离到单独的文件中,其他页面模板可以继承骨架文件
(1)向模板中导入变量:template.defaults.imports.变量名 = 变量值
(2)设置模板根目录:template.defaults.root = 模板目录
(3)设置模板默认后缀:template.defaults.extname = '.art'
原始语法
- 输出
<%=数据 %>
- 原文输出
<%-数据 %>
- 条件判断:
<% if(value){ %> ... <% } %>
<% if(v1){ %> ... <% }else if(v2){ %> ... <% } %>
- 循环:
<% for(var i = 0;i < target.length;i++){ %> <%= i %> <%= target[i] %> <% } %>
- 子模板:
<% include('模板(路径)') %>
- 模板继承
1-5语法规则案例:
// template/app.js
// 导入模板引擎
const template = require('art-template')
// 引入path模块
const path = require('path')
// 模板路径要用绝对路径
const views = path.join(__dirname,'views','index.art')
const html = template(views,{
name:'falcon',
age:20,
sex:'男',
content:'<h3>hello world</h3><p>love me love my dog</p>',
user:[{
"name":"falcon",
"age":20,
"password":"111111",
"email":"123@163.com",
},
{
"name":"alice",
"age":18,
"password":"222222",
"email":"124@163.com",
},
{
"name":"lily",
"age":21,
"password":"333333",
"email":"125@163.com",
},
{
"name":"rose",
"age":16,
"password":"555555",
"email":"126@163.com",
}],
msg:'welcome to home page'
})
console.log(html);
<!-- template/views/index.art -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<!-- 标准语法 -->
<!-- 1.输出 -->
{{name}}
{{age}}
<!-- 2.原文输出 -->
{{@ content}}
<!-- 3.判断 -->
{{if age===20}}
<h3>you are right</h3>
{{/if}}
{{if age===20}}
<h3>give me five</h3>
{{else if age===21}}
<h3>try again</h3>
{{/if}}
<!-- 4.循环 -->
{{each user}}
<li>{{$value.name}}</li>
<li>{{$value.age}}</li>
<li>{{$value.password}}</li>
<li>{{$value.email}}</li>
{{/each}}
<!-- 5.子模板 -->
{{ include './common/header.art' }}
<div>{{msg}}</div>
{{ include './common/footer.art' }}
<!-- 原始语法 -->
<!-- 1.输出 -->
<%= name %>
<%= age %>
<!-- 2.原文输出 -->
<%- content %>
<!-- 3.判断 -->
<% if(age === 20){ %>
<h3>bingo</h3>
<% } %>
<% if(sex === '女'){ %>
<h3>beautiful</h3>
<% }else if(sex === '男'){ %>
<h3>handsome</h3>
<% } %>
<!-- 4.循环 -->
<% for(var i = 0;i < user.length; i++){ %>
<li>
<%= i %>
<%= user[i].name %>
<%= user[i].age %>
<%= user[i].password %>
<%= user[i].email %>
</li>
<% } %>
<!-- 5.子模板 -->
<% include ('./common/header.art') %>
<div>{{msg}}</div>
<% include ('./common/footer.art') %>
</body>
</html>
<!-- template/views/common/header.art -->
这是头部
<!-- template/views/common/footer.art -->
这是尾部
6.模板继承案例:
// template/app.js
// 导入模板引擎
const template = require('art-template')
// 引入path模块
const path = require('path')
// 引入dateformat模块。时间格式化处理:1.安装dateformat 2.将模板引入进来 3.使用模板进行时间格式化
const dateFormat = require('dateformat')
// 模板路径要用绝对路径
// const views = path.join(__dirname,'views','index.art')
// const views = path.join(__dirname,'views','inherit.art')
// 设置模板根目录
template.defaults.root = path.join(__dirname,'views')
// 设置模板默认后缀
template.defaults.extname = '.art'
// 导入模板变量
template.defaults.imports.dateFormat = dateFormat
// const html = template(views,{
// 设置根目录之后,只需要填模板名称即可
// const html = template('inherit.art',{
// 设置模板默认后缀之后,只需要填模板名称即可
const html = template('inherit',{
msg:'welcome to home page',
time:new Date()
})
console.log(html);
<!-- template/views/inherit.art -->
<p>{{ msg }}</p>
<p>{{dateFormat(time,'yyyy-MM-dd HH:mm:ss')}}</p>
<!-- template/views/common/layout.art -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
{{block 'link'}} {{/block}}
</head>
<body>
{{block 'content'}} {{/block}}
</body>
</html>
静态资源访问处理
12.Express框架
特点
- 提供了方便简洁的路由定义方式
- 对获取HTTP请求参数进行了简化处理
- 对模板引擎的支持程度高,方便渲染动态HTML页面
- 提供了中间件机制有效控制HTTP请求
- 拥有大量第三方中间件对功能进行扩展
// 引入express框架
const express = require('express')
// 创建网站服务器
const app = express()
// 处理客户端发送的请求
// send即可以传字符串,也可以传json对象
app.get('/',(req,res) => {
// res.send('hello world')
res.send({'name':'falcon','age':20})
})
// 监听一个端口
app.listen(3000)
console.log('服务器启动成功!');
中间件
- 中间件就是一堆方法,可以接受客户端发来的请求、可以对请求作出响应,也可以将请求继续教给下一个中间件处理
- 可以对同一个请求设置多个中间件,对同一个请求进行多次处理
- 可以调用next方法将请求的控制权交给下一个中间件,直到遇到结束请求的中间件
两部分组成:中间件方法 和 请求处理函数
// 引入express框架
const express = require('express')
// 创建网站服务器
const app = express()
// 处理客户端发送的请求
// send即可以传字符串,也可以传json对象
app.get('/request',(req,res,next) => {
req.name = 'falcon',
next()
})
app.get('/request',(req,res) => {
res.send(req.name) //falcon
})
// 监听一个端口
app.listen(3000)
console.log('服务器启动成功!');
app.use中间件
// 引入express框架
const express = require('express')
// 创建网站服务器
const app = express()
// app.use 接受所有请求的中间件
app.use((req,res,next) => {
console.log('这是app.use中间件');
next()
})
// 当客户端访问 /request 请求的时候走当前中间件
app.use('/request',(req,res,next) => {
console.log('这是app.use 固定请求地址中间件');
next()
})
// 处理客户端发送的请求
// send即可以传字符串,也可以传json对象
app.get('/',(req,res) => {
res.send('home page')
})
app.get('/request',(req,res,next) => {
req.name = 'falcon',
next()
})
app.get('/request',(req,res) => {
res.send(req.name) //falcon
})
// 监听一个端口
app.listen(3000)
console.log('服务器启动成功!');
中间件的应用
// 引入express框架
const express = require('express')
// 创建网站服务器
const app = express()
app.use('/admin',(req,res,next) => {
// 设置登录状态
// let isLogin = false
let isLogin = true
if(isLogin){
next()
}else{
res.send('你还没登录,不能进行访问')
}
})
// 处理客户端发送的请求
// send即可以传字符串,也可以传json对象
app.get('/admin',(req,res,next) => {
res.send('已登录,可访问')
})
// 监听一个端口
app.listen(3000)
console.log('服务器启动成功!');
只需要在1.路由保护的app.use最前面加上一个app.use(接受所有的请求)
app.use((req,res,next) => {
res.send('网站正在维护,请稍后再试')
})
在1.路由保护的基础上,在请求的最后,加上一个app.use接受所有请求的中间件
// 自定义404页面
app.use((req,res,next) => {
// 默认的状态码为200,设置为404
res.status(404).send('当前访问的页面是不存在的')
})
错误处理中间件
// 引入express框架
const express = require('express')
// 创建网站服务器
const app = express()
// 请求抛出一个错误
app.get('/index',(req,res) => {
throw new Error('这是一个错误')
})
// 错误处理中间件
app.use((err,req,res,next) => {
res.status(500).send(err.message)
})
// 监听一个端口
app.listen(3000)
console.log('服务器启动成功!');
// 引入express框架
const express = require('express')
// 引入读取文件模块
const fs = require('fs')
// 创建网站服务器
const app = express()
// 请求抛出一个错误
app.get('/index',(req,res,next) => {
fs.readFile('./demo.txt','utf8',(err,result) => {
if(err != null){//读取失败
next(err)
}else{//文件读取成功
res.send(result)
}
})
})
// 错误处理中间件
app.use((err,req,res,next) => {
res.status(500).send(err.message)
})
// 监听一个端口
app.listen(3000)
console.log('服务器启动成功!');
捕获错误
// 引入express框架
const express = require('express')
// 引入promisify
const promisify = require('util').promisify
// 包装readFile方法
const readFile = promisify(fs.readFile)
// 创建网站服务器
const app = express()
app.get('/index',async (req,res,next) => {
// 进行错误的捕获
try{
await readFile('./demo.txt')
}catch(ex){
next(ex)
}
})
// 监听一个端口
app.listen(3000)
console.log('服务器启动成功!');
构建模块化路由
// route/home.js
// 引入express框架
const express = require('express')
// 创建路由对象
const home = express.Router()
// 路由对象处理
home.get('/index',(req,res) => {
res.send('welcome to home page')
})
// 将路由对象导出
module.exports = home;
// route/admin.js
// 引入express框架
const express = require('express')
// 创建路由对象
const admin = express.Router()
// 路由对象处理
admin.get('/index',(req,res) => {
res.send('welcome to admin page')
})
// 将路由对象导出
module.exports = admin;
// router.js
// 引入express框架
const express = require('express')
// 创建网站服务器
const app = express()
// 导入home路由模块
const home = require('./router/home')
// 导入admin路由模块
const admin = require('./router/admin')
// 使用home路由
app.use('/home',home)
// 使用admin路由
app.use('/admin',admin)
// 监听一个端口
app.listen(3000)
console.log('服务器启动成功');
GET、POST参数的获取
GET参数的获取
// 引入express框架
const express = require('express')
// 创建网站服务器
const app = express()
// 响应客户端的请求
app.get('/index',(req,res) => {
// 获取get请求参数
res.send(req.query)
})
// 监听端口
app.listen(3000)
console.log('服务器启动成功!');
POST参数的获取
//post.js
// 引入express框架
const express = require('express')
// 引入body-parser模块
const bodyParser = require('body-parser')
// 创建web服务器
const app = express()
// 拦截所有的请求
// extended:false 方法内部使用querystring模块处理请求参数的格式;extended:true 方法内部使用第三方模块qs处理参数的请求格式
app.use(bodyParser.urlencoded({extended:false}))
// 处理客户端的请求
app.post('/add',(req,res) => {
res.send(req.body)
})
// 监听一个端口
app.listen(3000)
console.log('服务器启动成功');
<!-- post.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>post参数的获取</title>
</head>
<body>
<form action="http://localhost:3000/add" method="POST">
<input type="text" name="username" id="">
<input type="password" name="password" id="">
<input type="submit" value="提交">
</form>
</body>
</html>
Express路由参数
// 引入express框架
const express = require('express')
// 创建web服务器
const app = express()
// 处理客户端的请求
app.get('/index/:id/:name/:age',(req,res) => {
res.send(req.params)
})
// 监听一个端口
app.listen(3000)
console.log('服务器启动成功');
静态资源的处理
// 有一个和static.js平级的public文件夹,用于存放静态资源
// 引入express框架
const express = require('express')
// 引入path模块
const path = require('path')
// 创建web服务器
const app = express()
// 实现静态资源的访问
app.use(express.static(path.join(__dirname,'public')))
// 监听一个端口
app.listen(3000)
console.log('服务器启动成功!');
模板引擎
然后需要在和template.js平级的目录中新建一个views文件夹,里面存放需要访问的 ‘.art’ 后缀的文件
// template.js
// 引入express框架
const express = require('express')
// 引入path模块
const path = require('path')
// 创建web服务器
const app = express()
// 1.告诉express框架使用什么模板引擎渲染什么后缀的模板文件:1模板的后缀;2使用的模板引擎
app.engine('art',require('express-art-template'))
// 2.告诉express框架模板存放的位置是什么
app.set('views',path.join(__dirname,'views'))
// 3.告诉express框架模板的默认后缀是什么
app.set('view engine','art')
app.get('/index',(req,res) => {
// res.render做了很多事情:1、拼接模板路径;2、拼接模板后缀;3、告诉模板引擎哪一个模板和哪一个数据进行拼接;4、把拼接的结果响应给客户端
res.render('index',{
msg:'hello world'
})
})
app.get('/list',(req,res) => {
res.render('list',{
msg:'list page'
})
})
// 监听一个端口
app.listen(3000)
console.log('服务器启动成功');
app.locals对象
将变量设置到app.locals对象下面,这个数据在所有的模板中都可以获取到
// app.locals 所有模板都可以获取到数据
// 在上面代码的基础上添加一个app.locals,则在views文件夹里面的.art文件都可以访问app.locals中所包含的文件
app.locals.users = [{
name:'falcon',
age:20
},{
name:'rose',
age:18
}]
<ul>
{{each users}}
<li>
{{$value.name}}
{{$value.age}}
</li>
{{/each}}
</ul>