NodeJS之搭建Web服务器
创始人
2024-04-03 06:23:07
0

文章目录

  • 认识NodeJS
  • 认识HTTP请求
  • 处理get请求
  • 处理post请求
  • 处理http请求总结
  • 博客项目实战
    • 搭建开发环境
    • 初始化路由
    • 开发第一个路由
    • 处理异步代码
      • 读取文件的例子
      • 处理POST数据
    • 开发新建、更新、删除博客的路由
      • 新建路由
    • 使用MySQL
    • NodeJS连接MySQL
    • 封装执行sql语句的工具函数
    • 获取博客列表接口对接MySQL
    • 博客详情、新建博客接口对接MySQL
    • 更新博客、删除博客接口对接MySQL

⭐️学习视频教程来自 B站

✨笔记源码——点击下载

认识NodeJS

javascript可以运行在浏览器上,因为google浏览器内置V8引擎

NodeJS是基于V8引擎的一个容器,又是C++编写的 所以JS代码也可以运行在NodeJS中

认识HTTP请求

  1. DNS解析,建立TCP连接,然后发起HTTP请求
  2. 服务端接收到HTTP请求,进行处理,返回数据
  3. 客户端接收到返回的数据,处理数据(例如渲染页面)

nodejs用url替换querystring

谷歌json格式美化插件:蓝奏云 密码:63mj

处理get请求

const http = require("http");
const url = require("url");const server = http.createServer((req, res) => {const method = req.method;console.log("method", method);let reqUrl = req.url;let query = url.parse(reqUrl, true).query;res.end(JSON.stringify(query));
});server.listen(5000, () => {console.log("server running at prot 5000");
});

在这里插入图片描述

处理post请求

const http = require("http");const server = http.createServer((req, res) => {if (req.method === "POST") {let postData = "";// 流streamreq.on("data", (chunk) => {postData += chunk.toString();});req.on("end", () => {console.log("postData", postData);res.end("数据接收完毕");});console.log("post data content type", req.headers["content-type"]);}
});server.listen(5000, () => {console.log("server running at prot 5000");
});

在这里插入图片描述

处理http请求总结

const http = require("http");
const url = require("url");const server = http.createServer((req, res) => {const method = req.method;const reqUrl = req.url;const path = reqUrl.split("?")[0];const query = url.parse(reqUrl, true).query;const responseData = {method,reqUrl,path,query,};res.setHeader("Content-Type", "application/json");if (method === "GET") {res.end(JSON.stringify(responseData));}if (method === "POST") {let postData = "";req.on("data", (chunk) => {postData += chunk.toString();});req.on("end", () => {responseData.postData = postData;res.end(JSON.stringify(responseData));});}
});server.listen(5000, () => {console.log("server running at prot 5000");
});

在这里插入图片描述

在这里插入图片描述

博客项目实战

搭建开发环境

npm init -y

npm install nodemon -D --registry=https://registry.npm.taobao.org

在这里插入图片描述
bin/www.js

// 创建服务器
const http = require("http");
const serverHandler = require("../app");
const PORT = 5000;const server = http.createServer(serverHandler);server.listen(PORT, () => {console.log("server running at prot 5000");
});

app.js

const serverHandler = (req, res) => {res.setHeader("Content-Type", "application/json");const responseData = {name: "nodeJS学习",age: 21,};res.end(JSON.stringify(responseData));
};module.exports = serverHandler;

在这里插入图片描述
在这里插入图片描述

初始化路由

src/routes/blog.js

// 处理博客相关的路由
const handleBlogRoute = (req, res) => {// 定义处理路由的逻辑const method = req.method;if (method === "GET" && req.path === "/api/blog/list") {return {message: "获取博客列表的接口",};}if (method === "GET" && req.path === "/api/blog/detail") {return {message: "获取博客详情的接口",};}if (method === "POST" && req.path === "/api/blog/new") {return {message: "新建博客接口",};}if (method === "POST" && req.path === "/api/blog/update") {return {message: "更新博客接口",};}if (method === "POST" && req.path === "/api/blog/delete") {return {message: "删除博客接口",};}
};module.exports = handleBlogRoute;

app.js

const handleBlogRoute = require("./src/routes/blog");
const serverHandler = (req, res) => {res.setHeader("Content-Type", "application/json");const url = req.url;req.path = url.split("?")[0];const blogData = handleBlogRoute(req, res);if (blogData) {res.end(JSON.stringify(blogData));return;}res.writeHead(404, { "Content-Type": "text/plain" });res.write("404 Not Found");res.end();
};module.exports = serverHandler;

在这里插入图片描述

开发第一个路由

想让返回的数据格式更加规范
src/model/responseModel.js

class BaseModel {constructor(data, message) {if (typeof data === "string") {this.message = data;data = null;message = null;}if (data) {this.data = data;}if (message) {this.message = message;}}
}// 成功模型
class SuccessModel extends BaseModel {constructor(data, message) {super(data, message);this.errno = 0;}
}// 失败模型
class ErrorModel extends BaseModel {constructor(data, message) {super(data, message);this.errno = -1;}
}module.exports = {SuccessModel,ErrorModel,
};

在这里插入图片描述在这里插入图片描述

src/controllers/blog.js

// 博客相关的方法
const getList = (author, keyword) => {// 从数据库里拿数据// 先返回假数据return [{id: 1,title: "标题1",content: "内容1",author: "zhangsan",createdAt: 1667208603225,},{id: 2,title: "标题2",content: "内容2",author: "zhangsan",createdAt: 1667208603277,},];
};module.exports = {getList,
};

在这里插入图片描述

处理异步代码

把获取博客详情的接口先补充一下
在这里插入图片描述在这里插入图片描述

在这里插入图片描述

post请求处理逻辑实际上是异步的

if (req.method === "POST") {let postData = "";// 流streamreq.on("data", (chunk) => {// 处理数据内容, 这里会是一个异步的过程postData += chunk.toString();});req.on("end", () => {console.log("postData", postData);res.end("数据接收完毕");});}

读取文件的例子

const fs = require("fs");
const path = require("path");// 读取文件内容
// function getFileContent(filename, callback) {
// 数据文件的绝对路径
//   const fullFilename = path.resolve(__dirname, "data", filename);//   fs.readFile(fullFilename, (err, data) => {
//     if (err) {
//       console.error(err);
//       return;
//     }//     callback(JSON.parse(data.toString()));
//   });
// }// 回调地狱
// getFileContent("a.json", (aData) => {
//   console.log("aData", aData);
//   getFileContent(aData.next, (bData) => {
//     console.log("bData", bData);
//     getFileContent(bData.next, (cData) => {
//       console.log("cData", cData);
//     });
//   });
// });function getFileContent(filename) {const promise = new Promise((resolve, reject) => {// 数据文件的绝对路径const fullFilename = path.resolve(__dirname, "data", filename);fs.readFile(fullFilename, (err, data) => {if (err) {reject(err);return;}resolve(JSON.parse(data.toString()));});});return promise;
}getFileContent("a.json").then((aData) => {console.log("aData", aData);return getFileContent(aData.next);}).then((bData) => {console.log("bData", bData);return getFileContent(bData.next);}).then((cData) => {console.log("cData", cData);});

在这里插入图片描述

处理POST数据

app.js

const handleBlogRoute = require("./src/routes/blog");
const url = require("url");// 处理POST数据
const getPostData = (req) => {const promise = new Promise((resolve, reject) => {if (req.method !== "POST") {resolve({});return;}if (req.headers["content-type"] !== "application/json") {resolve({});return;}let postData = "";req.on("data", (chunk) => {postData += chunk.toString();});req.on("end", () => {if (!postData) {resolve({});return;}resolve(JSON.parse(postData));});});return promise;
};
const serverHandler = (req, res) => {// 设置响应格式res.setHeader("Content-Type", "application/json");//   获取pathconst reqUrl = req.url;req.path = reqUrl.split("?")[0];//   解析queryreq.query = url.parse(reqUrl, true).query;// 处理POST数据getPostData(req).then((postData) => {req.body = postData;// 博客相关的路由const blogData = handleBlogRoute(req, res);if (blogData) {res.end(JSON.stringify(blogData));return;}// 未匹配到任何路由res.writeHead(404, { "Content-Type": "text/plain" });res.write("404 Not Found");res.end();});
};module.exports = serverHandler;

在这里插入图片描述

在这里插入图片描述

开发新建、更新、删除博客的路由

新建路由

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
src/controllers/blog.js

// 博客相关的方法
const getList = (author, keyword) => {// 从数据库里拿数据// 先返回假数据return [{id: 1,title: "标题1",content: "内容1",author: "zhangsan",createdAt: 1667208603225,},{id: 2,title: "标题2",content: "内容2",author: "zhangsan",createdAt: 1667208603277,},];
};const getDeatil = (id) => {// 先返回假数据return {id: 1,title: "标题1",content: "内容1",author: "zhangsan",createdAt: 1667208603225,};
};// 新建博客路由
const createNewBlog = (blogData) => {// blogData title contentconsole.log(blogData);return {id: 1,};
};// 更新
const updateBlog = (id, blogData) => {console.log("id", id);console.log("blogData", blogData);return true;
};
// 删除
const deleteBlog = (id) => {console.log("id", id);return true;
};
module.exports = {getList,getDeatil,createNewBlog,updateBlog,deleteBlog,
};

src/routes/blog.js

const {getList,getDeatil,createNewBlog,updateBlog,deleteBlog,
} = require("../controllers/blog");
const { SuccessModel, ErrorModel } = require("../model/responseModel");// 处理博客相关的路由
const handleBlogRoute = (req, res) => {// 定义处理路由的逻辑const method = req.method;const id = req.query.id;const blogData = req.body;// 博客列表路由if (method === "GET" && req.path === "/api/blog/list") {// /api/blog/list?author=zhangsan&keyword=123// new SuccessModel()const author = req.query.author || "";const keyword = req.query.keyword || "";const listData = getList(author, keyword);return new SuccessModel(listData);}// 博客详情路由if (method === "GET" && req.path === "/api/blog/detail") {const detailData = getDeatil(id);return new SuccessModel(detailData);}// 新建博客路由if (method === "POST" && req.path === "/api/blog/new") {const newBlogData = createNewBlog(blogData);return new SuccessModel(newBlogData);}// 更新博客路由if (method === "POST" && req.path === "/api/blog/update") {const updateBlogData = updateBlog(id, blogData);if (updateBlogData) {return new SuccessModel("更新博客成功");} else {return new ErrorModel("更新博客失败...");}}// 删除博客路由if (method === "POST" && req.path === "/api/blog/delete") {const deleteBlogData = deleteBlog(id, blogData);if (deleteBlogData) {return new SuccessModel("删除博客成功");} else {return new ErrorModel("删除博客失败...");}}
};module.exports = handleBlogRoute;

使用MySQL

在这里插入图片描述

use myblog;-- show tables;-- insert into blogs (title, content, author, createAt) values ('标题2', '内容2', 'zhangsan', 1234567890888)-- select * from blogs;
-- select id, author from blogs;
-- select count(*) as total from blogsselect * from blogs where author like '%zhang%' order by id desc;
update blogs set content="内容1" where id=1
delete from blogs where title="标题2"; -- 不安全

在这里插入图片描述

update blogs set status='0' where author='zhangsan' -- 软删除
select * from blogs where status<>0

NodeJS连接MySQL

npm i mysql

const mysql = require("mysql");// 创建连接对象
const connection = mysql.createConnection({host: "localhost",user: "root",password: "IKUN1220",port: 3306,database: "myblog",
});
// 开始连接
connection.connect();
// 执行sql
const sql = `select * from blogs`;
connection.query(sql, (error, result) => {if (error) {console.error(error);return;}console.log("result", result);
});
// 关闭连接
connection.end();

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

封装执行sql语句的工具函数

src/db/mysql.js

const mysql = require("mysql");
const { MY_CONFIG } = require("../config/db");// 创建连接对象
const connection = mysql.createConnection(MY_CONFIG);
// 开始连接
connection.connect();
// 执行sql// function execSQL(sql, callback) {
//   connection.query(sql, callback);
// }// promise优化 避免出现回调地狱
function execSQL(sql) {const promise = new Promise((resolve, reject) => {connection.query(sql, (err, result) => {if (err) {reject(err);return;}resolve(result);});});return promise;
}module.exports = {execSQL,
};

src/config/db.js

let MY_CONFIG = {};MY_CONFIG = {host: "localhost",user: "root",password: "IKUN1220",port: 3306,database: "myblog",
};module.exports = {MY_CONFIG,
};

在这里插入图片描述

获取博客列表接口对接MySQL

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

博客详情、新建博客接口对接MySQL

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

更新博客、删除博客接口对接MySQL

// 更新
const updateBlog = (id, blogData = {}) => {const title = blogData.title;const content = blogData.content;const sql = `update blogs set title = '${title}', content = '${content}' where id = ${id}`;return execSQL(sql).then((updateResult) => {console.log("updateResult", updateResult);if (updateResult.affectedRows > 0) {return true;}return false;});
};
-------------------
// 更新博客路由if (method === "POST" && req.path === "/api/blog/update") {const updateBlogDataPrmise = updateBlog(id, blogData);return updateBlogDataPrmise.then((updateBlogData) => {if (updateBlogData) {return new SuccessModel("更新博客成功");} else {return new ErrorModel("更新博客失败...");}});}

在这里插入图片描述

// 删除
const deleteBlog = (id) => {const sql = `delete from blogs where id = ${id}`; //实际开发使用update进行软删除return execSQL(sql).then((deleteResult) => {if (deleteResult.affectedRows > 0) {return true;}return false;});
};------
// 删除博客路由if (method === "POST" && req.path === "/api/blog/delete") {const deleteBlogDataPromise = deleteBlog(id);return deleteBlogDataPromise.then((deleteBlogData) => {if (deleteBlogData) {return new SuccessModel("删除博客成功");} else {return new ErrorModel("删除博客失败...");}});}

在这里插入图片描述
删除还要对作者进行一个限制,只有对应的作者才能够删除

// 删除
const deleteBlog = (id, author) => {const sql = `delete from blogs where id = ${id} and author = '${author}'`;return execSQL(sql).then((deleteResult) => {if (deleteResult.affectedRows > 0) {return true;}return false;});
};
---------------
// 删除博客路由if (method === "POST" && req.path === "/api/blog/delete") {// 未写登录 暂时写死const author = "zhangsan";const deleteBlogDataPromise = deleteBlog(id, author);return deleteBlogDataPromise.then((deleteBlogData) => {if (deleteBlogData) {return new SuccessModel("删除博客成功");} else {return new ErrorModel("删除博客失败...");}});}

相关内容

热门资讯

银河麒麟V10SP1高级服务器... 银河麒麟高级服务器操作系统简介: 银河麒麟高级服务器操作系统V10是针对企业级关键业务...
【NI Multisim 14...   目录 序言 一、工具栏 🍊1.“标准”工具栏 🍊 2.视图工具...
AWSECS:访问外部网络时出... 如果您在AWS ECS中部署了应用程序,并且该应用程序需要访问外部网络,但是无法正常访问,可能是因为...
不能访问光猫的的管理页面 光猫是现代家庭宽带网络的重要组成部分,它可以提供高速稳定的网络连接。但是,有时候我们会遇到不能访问光...
AWSElasticBeans... 在Dockerfile中手动配置nginx反向代理。例如,在Dockerfile中添加以下代码:FR...
Android|无法访问或保存... 这个问题可能是由于权限设置不正确导致的。您需要在应用程序清单文件中添加以下代码来请求适当的权限:此外...
月入8000+的steam搬砖... 大家好,我是阿阳 今天要给大家介绍的是 steam 游戏搬砖项目,目前...
​ToDesk 远程工具安装及... 目录 前言 ToDesk 优势 ToDesk 下载安装 ToDesk 功能展示 文件传输 设备链接 ...
北信源内网安全管理卸载 北信源内网安全管理是一款网络安全管理软件,主要用于保护内网安全。在日常使用过程中,卸载该软件是一种常...
AWS管理控制台菜单和权限 要在AWS管理控制台中创建菜单和权限,您可以使用AWS Identity and Access Ma...