从零开始学Express,理解服务器,路由于中间件

        当我们初学前端时,常常只关注页面效果和交互,但随着项目复杂度提升,我们迟早会遇到“服务端”的问题:如何让一个页面的数据是从数据库来的?怎么让不同的用户看到不同的内容?这时候,我们就需要一个后端框架来帮我们处理这些需求。而对于 JavaScript 开发者来说,Express 是入门服务端开发最友好的一把钥匙。

        本文不会长篇大论地讲解底层原理,而是通过最直观、最简单的方式,带你快速理解:什么是服务器、路由、中间件,以及 Express 的核心用法。如果你刚刚接触 Node.js,希望用它写点后端的东西,这篇文章就是为你准备的。

 1.Express的简单使用

        express 是node中的服务器软件(封装的http模块),通过express可以快速的在node中搭建一个web服务器。

        使用步骤

        1.创建初始化项目

                创建文件夹然后终端输入 npm init -y

        2.安装express

                npm install express

      3.创建index.js 编写代码

//引入express
const express = require('express')
//一切皆对象服务器在程序里面也是对象
//获取服务器的实例对象
const app = express()
/*如果希望服务器可以正常访问 则需要为服务器设置路由路由可以根据不同的请求方式和请求地址来处理用户请求app.METHOD(...)METHOD可以是get post中间件-在express中我们使用app.use定义一个中间件中间件和路由很像 用法很像通常情况下 我们访问的直接是路由 但是有时候想要加一个中间件但是路由不区分请求的方式 只看路径只要访问的路径包含它就可以访问到和路由的区别1.会匹配所有的请求2.路径设置父目录
*/
//中间件
//next是回调函数的第三个参数 调用函数后可以触发后续的中间件 
app.use('/',(req,res,next)=>{console.log('收到请求')// res.send('中间件给你的响应')next()//next不能在响应处理完毕之后调用
})
app.use('/',(req,res)=>{console.log('收到请求')res.send('中间件给你的响应2222')})
//中间件用来干嘛 可以用来设置访问路由之前的权限 相当于访问路由之前设置一些(公关)处理
//http://localhost:3000 
//现在创建了一个路由 / (路由是接口)
//路由的回调函数执行的时候 会接受三个参数
//第一个 request 第二个response 
app.get('/hello',(req,res)=>{console.log('有人访问我了')//在路由中 应该做两件事//读取用户的请求(request)//req表示用户的请求信息 通过req可以获取用户的传递数据console.log(req.url)//用户请求的路由//根据用户的请求返回响应(response)//res表示服务器发送给客户端的响应信息//sendStatus()像客户端发送响应状态码// res.sendStatus(9999999)//status只是设置了状态码没有发送res.status(200)//send设置发送响应体res.send('这是我给你的东西 但其实没东西')
})
//启动服务器
//app.listen(端口号)用来启动服务器
//服务器就像一个房子就我们的计算机有非常多的软件
//怎么识别我们的服务器软件 
//端口楼里面的门牌号 3000端口号房间号 就是express服务你
//后面可以加一个回调函数 服务器启动后执行函数 现在可以通过3000端口访问服务器
//协议名://ip地址:端口号/路径
//http://localhost:3000/index.js localhost ===  127.0.0.1都是指本计算机
app.listen(3000,()=>{console.log('服务器已经启动')
})

        这就是一个基础的使用,我们访问http://localhost:3000/hello就会返回给你send()里面的内容。状态码在自定义,定义接收请求的路由格式app.METHOD('路径',(req,res)=>{})req,res通过传递函数调用函数时候参数拿过来直接用,这里就是我们的请求信息和响应信息。 

        中间件就是当我们访问路由的时候,如果设置了中间件,就会被中间件拦截,这里就是可以给路由设置一些权限要求等。

2.nodemon工具以及中间件的作用

       目前服务器代码修改后必须重启,希望有一种方式可以监视代码的修改。代码修改以后可以自动重启服务器 需要安装一个模块 nodemon(监视器)

        使用方式

                1.全局安装 npm install nodemon -g

        终端输入nodemon 就可以了 修改代码可以自动重启

        默认启动当前目录的index.js 如果不是index.js 加上名字 nodemon ./01_helloworld.js

                2.在项目中安装 npm install nodemon -D 开发依赖

                启动 npx nodemon npx执行node模块

        当我们创建express实例之后,实际上express有非常多的功能的。但是我们需要在中间件之中进行配置。比如我们希望当我们get访问http://localhost:3000/index.html。

        也就是服务器的代码希望可以被外部直接访问,我们就需要在中间件中配置静态资源目录。可以将页面html以及图片放进去这样可以从服务器获取到这些代码。

const express = require('express')
const path = require('node:path')
//创建服务器实例
const app = express()
//use()中间件
//配置路由 
//设置这个中间件之后 浏览器访问时会自动去public目录下寻找是否有静态资源
app.use(express.static(path.resolve(__dirname,'./public')))
app.get('/',(req,res)=>{/*希望用户访问我的根目录 我可以返回一个网页*/res.send('')
})
app.get('/login',(req,res)=>{//获取到用户名和密码//req.query表示查询字符串中的请求参数console.log(req.query)console.log(req.query.username)if(req.query.username==='奥巴马'&&req.query.password==='123123'){console.log('请求收到')res.send('登录成功')}else{res.send('登录失败')}
})
//启动服务器
app.listen(3000,()=>{console.log('服务器启动')
})

        这样我们就可以直接从浏览器获取到服务器中的页面了。用express.static设置静态文件目录,然后把希望外部可以直接访问的资源放进去就可以了。就可以通过文件名直接访问了。

        这里req和res就是请求和响应信息。

3.get请求的两种参数传递以及post请求

           1.get请求

 <form action="/login" method="get"><div>用户名 <input type="text" name="username"></div><div>密码 <input type="text" name="password"></div><div><input type="submit" value="登录"></div></form>
const express = require('express')
const path = require('node:path')
const app = express()
//配置一个静态资源的路径
//express很多功能都是中间件引入的
app.use(express.static(path.resolve(__dirname,'./public')))
//引入解析请求体的中间件
app.use(express.urlencoded())
///开头的路径 叫做绝对路径 /login实际上是 http://localhost/login
app.get('/login',(req,res)=>{if(req.query.username==='admin'&&req.query.password === '123123'){res.send('<h1>登录成功</h1>')}else{console.log('<h1>登录失败</h1>')}
})

        当我们直接用get方法发送请求的时候,我们在输入框输入的数据会在req.quert中以对象的形式传递过来,而我们直接在路径上设置参数的话。

//get请求发送参数第二种方式
///hello/:id 表示访问/hello/xxx时就会触发
//在路径中以冒号命名的部分我们称为param 在get请求它会被解析为请求参数
//params传递参数一般不会特别复杂 一般就是一个
app.get('/hello/:id',(req,res)=>{//约定由于配置//可以通过req.params获取参数console.log(req.params)//{ id: '123', age: '12', gender: '男' }res.send('<h1>这是hello路由</h1>')
})

        就会存储到params中,而且这个参数是在地址栏里面填写的。两种方式本质是相同的,params按照顺序传递。

        2.post请求

        post请求需要请求体,也就是body。但是我们express默认是没有给我们添加这个功能的,我们可以用中间件添加这个功能。

//引入解析请求体的中间件
app.use(express.urlencoded())
app.post('/login',(req,res)=>{console.log(req.query) //{}//默认情况下express不会自动解析请求体 需要中间件添加功能console.log(req.body)const username = req.body.usernameconst password = req.body.passwordif(username==='admin'&&password==='123123'){res.send('<h1>登录成功</h1>')}else{res.send('登录失败')}
})

        然后就可以接收post请求了。参数通过body拿取。

4.简单的登录案例 

        我们现在会写get和post路由了,那么我们就可以写简单的登录案例,比如当我们登录的时候,发送请求到这个路由,然后携带参数过来。我们提前写死一些账户然后进行对比,有的话就登录没有的话就返回登录失败。还有注册功能,当我们访问的注册路由的时候,携带参数过来,如果写死的账户里面没有,那么就用数组的方法把注册的参数数据推进去形成新用户。

<!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><h1>我是一个静态网页</h1><hr><h2>登录</h2><form action="/register" method="post"><div>用户名 <input type="text" name="username"></div><div>密码 <input type="password" name="password"></div><div>确认密码 <input type="password" name="repwd" placeholder="确认密码"></div><div><input type="texx" name="nickname" placeholder="昵称"></div><div><input type="submit" value="登录"></div></form>
</body>
</html>
const express = require('express')
const path = require('node:path')
const app = express()
//创建一个数组存储用户信息
const USERS =[{username:'admin',password:'123123',nickname:'超级管理员'},{username:'孙悟空',password:'123123',nickname:'用户'}
]
app.use(express.static(path.resolve(__dirname,'./public')))
app.use(express.urlencoded())
app.get('/login',(req,res)=>{if(req.query.username==='admin'&&req.query.password === '123123'){res.send('<h1>登录成功</h1>')}else{res.send('登录失败')console.log('<h1>登录失败</h1>')}
})
app.get('/hello/:id',(req,res)=>{//约定由于配置//可以通过req.params获取参数console.log(req.params)//{ id: '123', age: '12', gender: '男' }res.send('<h1>这是hello路由</h1>')
})
app.post('/login',(req,res)=>{const username = req.body.usernameconst password = req.body.password// USERS.map(user=>{//     if(user.username === username){//         if(user.password===password){//             res.send(登录成功 ${user.nickname})//             return//         }//     }// })// res.send('登录失败')const loginUser = USERS.find(item=>{return item.username === username && item.password===password})if(loginUser){res.send(登录成功 ${loginUser.nickname})}else{res.send('登录失败')}// if(username==='admin'&&password==='123123'){// res.send('<h1>登录成功</h1>')}// else{//     res.send('登录失败')// }
})
app.post('/register',(req,res)=>{//获取用户登录的数据console.log(req.body)const {username,password,repwd,nickname} = req.body//只验证用户名是否存在const user = USERS.find(item=>{return item.username === username || item.nickname === nickname})if(!user){//进入判断用户不存在USERS.push({username,password,nickname})res.send('恭喜你注册成功')}else{res.send('用户名存在')}})
//params以及查询字符串本质上没有区别 查询字符串对象形式传递参数 params按照顺序传
app.listen(3000,()=>{console.log('服务器启动了')
})

        这些代码就实现了登录注册的基本功能。

5.模板引擎 

        当然学后端node.js只是了解基本使用,比较现在还是主打前端开发。这里我们默认没有前端动态展示数据库数据,我们现在服务器写死一些数据希望可以去动态的展示,我们希望有一个东西,可以嵌套变量,在node里面叫做模板。

        html是静态页面 不会跟随服务器数据变化而变化。希望有一个东西 长的像网页 但是可以嵌套变量 这个东西node里面叫做模版。node存在很多个模版引擎 template engines 比如ejs。

       ejs是node中的一款模版引擎 使用步骤

                1.安装ejs

                2.配置express模版引擎为ejs

                        app.set('view engine','ejs')

                3.配置模版路径

                        app.set('views',path.resolve(__dirname,'views'))

        注意 模版引擎需要被express渲染后用户才能使用

        res.render()用来渲染一个模版引擎并将其返回给浏览器 render就是把ejs渲染并且返回给用户跟react 一样的 只不过react在前端这里是后台 后端环境。

        这是模板的目录需要放到views文件夹中。

const express = require('express')
const app = express()
const path = require('node:path')
const STUDENT = [{name:'sun',age:123,gender:'男',address:'花果山'},{name:'zhu',age:231,gender:'女',address:'高老庄'}
]
//将ejs配置为默认的模版引擎
app.set('view engine','ejs')
//配置模版路径
app.set('views',path.resolve(__dirname,'views'))
//配置静态资源路径
app.use(express.static(path.resolve(__dirname,'public')))
//配置请求体解析 body 
app.use(express.urlencoded())
//解析json请求体
//app.use(express.json())
/*可以写路由了
*/
app.get('/hello',(req,res)=>{res.send('hello')
})
//我们希望用户访问student路由的时候 可以返回一个页面里面有表格 存放的student数据
app.get('/students',(req,res)=>{//render可以将一个对象作为render的第二个参数传递 这样在模版中可以访问到对象中的数据//res.render('students',{name:'sun',age:'18'})//名字和ejs名一致//<%=name %>在ejs输出内容时 自动对字符串中的特殊符号进行转义 < 不会识别为标签//这个设计主要是为了避免xss 攻击//<%- %>会直接运行h1 以及js脚本等等res.render('students',{STUDENT})
})
//在所有路由的后面配置错误路由
//不写路径会匹配所以路径 上面路由都没有匹配到
app.use((req,res)=>{//这个执行 上面的路由都没有匹配res.status(404)res.send('你访问的地址被外星人劫持')
})
app.listen(3000,()=>{console.log('服务器已经启动')
})

        这里我们用render去渲染我们的模块,这样访问这个路由就可以返回一个页面给浏览器。然后第二个参数是对象,可以将动态展示的数据传递到模板,模板进行展示。

         

        这里是模板的写法,仍然是html写法只不过变量需要用<%= %>获取js代码需要<%%>包裹。

        

        说到底,Express 并不是一个神秘的东西,它只是对原生 Node HTTP 模块的一层“封装和简化”。我们只要记住三件事:

        它帮我们创建服务器(app.listen())

        它让我们能轻松写路由处理请求(app.get()、app.post())

        它通过中间件机制帮我们定制各种服务逻辑

        加上它对静态资源、模板引擎的良好支持,我们就能快速搭建出一个真正能跑的 Web 项目。

         

 

 

         

         

        

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/diannao/94543.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/94543.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Codeforces Round 987 (Div. 2)

ABC 略D预处理出每个位置的前缀最大和后缀最小。从后向前枚举&#xff0c;如果一个数无法后移&#xff0c;那么答案就是最大前缀&#xff0c;否则答案要不是前缀最大&#xff0c;要不就是这个数先移到前缀最大位置再移到能移到的最大的位置此处的答案。用线段树维护#include<…

Javascript/ES6+/Typescript重点内容篇——手撕(待总结)

前端核心知识点梳理与面试题详解 1. Promise 核心知识点 Promise 是异步编程的解决方案&#xff0c;用于处理异步操作三种状态&#xff1a;pending&#xff08;进行中&#xff09;、fulfilled&#xff08;已成功&#xff09;、rejected&#xff08;已失败&#xff09;状态一旦改…

[自动化Adapt] 父子事件| 冗余过滤 | SQLite | SQLAlchemy | 会话工厂 | Alembic

第五章&#xff1a;事件处理与融合 欢迎回到OpenAdapt探索之旅~ 在第四章&#xff1a;系统配置中&#xff0c;我们掌握了如何定制化系统参数。更早的第一章&#xff1a;录制引擎则展示了系统如何捕获海量原始操作数据。 假设我们需要训练机器人输入"hello"一词。原…

组合期权:跨式策略

文章目录0.简介1.买入跨式组合&#xff08;Long Straddle&#xff09;1.1 适用场景​1.2 合约选择1.3 损益分析1.4 案例示范2.卖出跨式组合&#xff08;Short Straddle&#xff09;2.1 适用场景​2.2 合约选择2.3 损益分析2.4 案例示范3.小结参考文献0.简介 跨式策略是一种交易…

Vue计算属性详解2

可写计算属性 计算属性默认是只读的,但在特殊场景下,我们可以创建"可写"的计算属性,通过同时提供getter和setter实现: <script setup>import { ref, computed } from vueconst firstName = ref(John)const lastName = ref(Doe)const fullName = computed(…

UniStorm 5.3.0 + Unity2022 + URP配置说明

一、前言 以前我用的是UniStorm3.0&#xff0c;主要用在内置管线里面&#xff0c;最近想在URP管线里面使用UniStorm天气系统&#xff0c;于是弄了UniStorm5.3.0的包&#xff0c;在Unity2022.3的URP模式下配置&#xff0c;直接导入package&#xff0c;两次宣告失败。最后看了官方…

力扣经典算法篇-44-组合总和(回溯问题)

1、题干 给你一个无重复元素的整数数组candidates和一个目标整数 target &#xff0c;找出 candidates 中可以使数字和为目标数 target 的 所有 不同组合 &#xff0c;并以列表形式返回。你可以按 任意顺序 返回这些组合。 candidates 中的 同一个 数字可以 无限制重复被选取 。…

矩阵与高斯消元:数学算法在计算机领域的应用

一、概述和基本概念 矩阵&#xff0c;类似于在 C 中我们看到的二维数组。它有两个维度&#xff0c;行和列。下面是一个典型的矩阵&#xff1a; M[12342345445610111213] M \begin{bmatrix} 1 & 2 & 3 & 4 \\ 2 & 3 & 4 & 5 \\ 4 & 4 & 5 &…

【补题】CodeTON Round 1 (Div. 1 + Div. 2, Rated, Prizes!) D. K-good

题意&#xff1a;给一个n&#xff0c;如果能被k个数整除&#xff0c;要求这k个数%k后不相同&#xff0c;问如果可以&#xff0c;任意k是多少&#xff0c;如果不可以输出-1 思路&#xff1a; D. K-good_牛客博客 从来没见过&#xff0c;太诡异了&#xff0c;做题做少了 1.…

LLM推理框架的“权力的游戏”:vLLM之后的群雄逐鹿

既然我们已经深入探讨了本地与云端的两大代表Ollama和vLLM&#xff0c;是时候将视野拓宽&#xff0c;检视一下在高性能推理这片“高手如云”的竞技场中&#xff0c;还有哪些重量级的玩家。vLLM的出现点燃了战火&#xff0c;但远非终点。 欢迎来到LLM推理框架的“后vLLM时代”—…

TDengine IDMP 背后的技术三问:目录、标准与情景

过去十年&#xff0c;#工业 和#物联网 场景经历了快速的#数字化 建设&#xff1a;传感器接入、系统联网、数据上云……数据平台已能轻松承载每秒千万级别的写入&#xff0c;每天几 TB 的存储量。但今天再回头看&#xff0c;这些看似“完成”的系统&#xff0c;实际上只解决了一…

MyBatis基础操作完整指南

文章目录MyBatis简介环境搭建Maven依赖数据库表结构核心配置MyBatis配置文件数据库配置文件实体类基础CRUD操作Mapper接口Mapper XML映射文件工具类测试类动态SQL常用标签高级特性一对一关联映射一对多关联映射分页查询使用注解方式MyBatis简介 MyBatis是Apache的一个开源项目…

go与grpc

目录下载与安装遇到的问题cmd中protoc找不到命令cmd中--go_out: protoc-gen-go: Plugin failed with status code 1.下载与安装 下载protoc&#xff1a; https://github.com/protocolbuffers/protobuf/releases 点击下载相应电脑版本即可&#xff0c;我是windows系统下载了pro…

2025年AI面试重构招聘新生态

当企业面临业务扩张与人才竞争的双重压力&#xff0c;传统招聘模式已难以满足高效、精准、公平的人才筛选需求。尤其在校招季、蓝领用工潮等关键节点&#xff0c;面试官超负荷运转、跨地域协调困难、评估标准模糊等问题频发。AI技术的深度介入正推动招聘行业从“经验驱动”向“…

Rust进阶-part5-trait

Rust进阶[part5]_trait trait概述 在 Rust 中,trait 是一种定义共享行为的方式。它类似于其他语言中的接口,允许我们定义一组方法签名,然后让不同的类型去实现这些方法。通过 trait,我们可以实现多态性,即不同类型可以以统一的方式处理。 普通实现 使用 trait 关键字来…

【人工智能-18】机器学习:决策树、随机森林

上一期【人工智能-17】机器学习&#xff1a;KNN算法、模型选择和调优、朴素贝叶斯分类 文章目录一、决策树1.使用理由2.技术二、随机森林1.使用理由2.原理核心&#xff1a;Bagging 随机特征子集3.优点和缺点一、决策树 决策树是一种监督学习算法&#xff0c;主要用于分类&…

RFID高频读写器在工业生产线的使用优势

在工业4.0浪潮下&#xff0c;智能制造对生产效率与精准度的要求日益提升。RFID技术凭借其独特的技术优势&#xff0c;成为工业场景中实现数据实时采集与流程优化的关键工具。本文主要从RFID高频读写器出发&#xff0c;系统解析其在工业生产线中的使用优势。RFID高频读写器一、技…

大模型学习笔记

prompt 提示词的构成&#xff1a; 指示&#xff1a;描述让它做什么上下文&#xff1a;给出与任务相关的背景信息输入&#xff1a; 任务的输入信息输出&#xff1a;输出的格式 生成与检索 生成&#xff1a; 优点&#xff1a;内容的多样性、创造性缺点&#xff1a;存在不可控制 检…

龙虎榜——20250806

上证指数继续收阳线&#xff0c;创新高的概率较大&#xff0c;个股上涨多于下跌&#xff0c;但板块轮动较明显&#xff0c;高位板块注意风险。深证指数较昨天放量收阳线&#xff0c;站上5日和10日均线继续上线&#xff0c;大科技方向资金关注更多。2025年8月6日龙虎榜行业方向分…

数据可视化发展历程

数据可视化是数据描述的图形表示&#xff0c;是当今数据分析发展最快速、最引人注目的领域之一。借助于可视化工具的发展&#xff0c;或朴实&#xff0c;或优雅&#xff0c;或绚烂的可视化作品给我们讲述着各种数据故事。在这个领域中&#xff0c;科学、技术和艺术完美地结合在…