http 請求
- 實現get請求數據庫數據;
- 實現添加數據
- 實現編輯數據
- 實現刪除數據
- 實現導出txt文件、Excel文件
- 實現查詢數據庫數據并利用導出為excel文件
node 版本 16.16.0
node 版本 18.16.0 會連接 MongoDB 數據庫錯誤。
Connected to MongoDB failed MongoServerSelectionError: connect ECONNREFUSED ::1:27017
{"name": "http-node-demo","version": "1.0.0","description": "","main": "index.js","scripts": {"test": "echo \"Error: no test specified\" && exit 1","start": "node index.js"},"author": "","license": "ISC","type": "module","dependencies": {"body-parser": "^1.20.2","mongodb": "^6.8.0","querystring": "^0.2.1"}
}
項目安裝 MongoDB 的 node 版本要跟啟動時的 node 版本一致,否則會報錯
const timeoutError = new error_1.MongoServerSelectionError(`Server selection timed out after ${options.serverSelectionTimeoutMS} ms`,this.description
);
node 鏈接 MongoDB
// MongoDB連接配置
const mongoConfig = {url: "mongodb://localhost:27017",dbName: "note", //數據庫名稱
};
import { MongoClient } from "mongodb";
import { mongoConfig } from "./default.js";
const mongoDB = new MongoClient(mongoConfig.url);let db;async function mainFun() {// 創建MongoDB連接try {await mongoDB.connect();console.log("Connected to MongoDB successfully");db = mongoDB.db(mongoConfig.dbName);} catch (err) {console.log("Connected to MongoDB failed", err);}
}export { mainFun, db };
接口返回的形勢
- 返回 404
// 解析url
const urlObj = new URL(req.url, `http://${req.headers.host}`);const params = {};
const apiKey = `${urlObj.pathname}&${req.method.toLocaleLowerCase()}`;
const item = ALL_PATH.find((v) => `/${v}` == apiKey);// 找不到路由,返回404 Not Found
if (!item) {res.writeHead(404, {"Content-Type": "text/plain; charset=utf-8",}).end("Not Found");return;
}
- 普通 JSON 字符串
import { db } from "../mongoDB/index.js";
const getUser = async () => {try {// 查詢數據集合user的所有數據并轉為數組形式const collection = await db.collection("user").find({}).toArray();let total = 0;collection.estimatedDocumentCount(function (err, count) {if (err) throw err;total = count;console.log("Estimated total number of documents: ", count);// client.close();});return {code: 200,data: {list: collection,total: total || 0,},};} catch (err) {return {code: 500,data: {list: [],total: 0,},};}
};
- 返回文件流
import fs from "fs";
import path from "path";const __dirname = path.resolve();const downloadDocs = async () => {const promise = new Promise((resolve, reject) => {fs.readFile(__dirname + "/docs/新建文本文檔.txt", (err, data) => {if (err) {console.error(err);reject("error");return;}resolve(data);});});try {const resData = await promise;return {code: 200,data: resData,contentType: "text/plain; charset=utf-8",};} catch (err) {return {code: 500,data: "",contentType: "text/plain; charset=utf-8",};}
};const downloadNoteTemplate = async () => {try {const data = fs.readFileSync(__dirname + "/docs/Note模板.xlsx");return {code: 200,data: data,contentType: "application/vnd.ms-excel; charset=utf-8",};} catch (err) {return {code: 500,data: "",contentType: "application/vnd.ms-excel; charset=utf-8",};}
};
resData {code: 200,data: <Buffer 50 4b 03 04 0a 00 00 00 00 00 87 4e e2 40 00 00 00 00 00 00 00 00 00 00 00 00 09 00 00 00 64 6f 63 50 72 6f 70 73 2f 50 4b 03 04 14 00 00 00 08 00 87 ... 9951 more bytes>,contentType: 'text/plain; charset=utf-8'
}
響應頭
當標頭已使用 response.setHeader()
設置時,則它們將與任何傳給 response.writeHead()
的標頭合并,其中傳給 response.writeHead()
的標頭優先。
語法
response.writeHead(statusCode[, statusMessage][, headers])
response.setHeader('Content-Type', 'text/html');
response.setHeader('Set-Cookie', ['type=ninja', 'language=javascript']);
// Returns content-type = text/plain
const server = http.createServer((req, res) => {res.setHeader("Content-Type", "text/html");res.setHeader("X-Foo", "bar");res.writeHead(200, { "Content-Type": "text/plain" });res.end("ok");
});
返回 xlsx 文件,前端下載處理
后端接口
const downloadNoteTemplate = async () => {try {const data = fs.readFileSync(__dirname + "/docs/Note模板.xlsx");return {code: 200,data: data,contentType: "application/vnd.ms-excel; charset=utf-8",};} catch (err) {return {code: 500,data: "",contentType: "application/vnd.ms-excel; charset=utf-8",};}
};
前端下載處理
<Button onClick={() => {request('/download/noteTemplate',{method: 'get',{/* */}responseType: "blob",responseEncoding: "utf8",options: {returnDirect: true, //returnDirect 直接返回接口所有信息},}).then((res) => {console.log('res',res);downloadContentFileFun('測試.xlsx',res)})
}}>下載</Button>
export const downloadContentFileFun = (filename, text) => {// 下載Excel的文件, type: "application/vnd.ms-excel"需要與后端返回的content保持一致,否則會出現無法打開的情況let blob = new Blob([text], { type: "application/vnd.ms-excel" });const element = document.createElement("a");const href = URL.createObjectURL(blob);element.href = href;element.setAttribute("download", filename);element.style.display = "none";element.click();//調用這個方法來讓瀏覽器知道不用在內存中繼續保留對這個文件的引用了。URL.revokeObjectURL(href);element.remove();
};
返回 txt 文件,前端下載處理
后端接口
const downloadDocs = async () => {const promise = new Promise((resolve, reject) => {fs.readFile(__dirname + "/docs/新建文本文檔.txt", (err, data) => {if (err) {console.error(err);reject("error");return;}resolve(data);});});try {const resData = await promise;return {code: 200,data: resData,contentType: "text/plain; charset=utf-8",};} catch (err) {return {code: 500,data: "",contentType: "text/plain; charset=utf-8",};}
};
前端下載處理
<ButtononClick={() => {request("download/homeDoc", {method: "get",responseType: "blob",responseEncoding: "utf8",options: {returnDirect: true, //returnDirect 直接返回接口所有信息},}).then((res) => {console.log("res", res);downloadContentFileFun("測試.txt", res);});}}
>下載
</Button>
export const downloadContentFileFun = (filename, text) => {// 這里的類型type改成application/vnd.ms-excel,發現也是可以正常打開的let blob = new Blob([text], { type: "text/plain; charset=utf-8" });const element = document.createElement("a");const href = URL.createObjectURL(blob);element.href = href;element.setAttribute("download", filename);element.style.display = "none";element.click();//調用這個方法來讓瀏覽器知道不用在內存中繼續保留對這個文件的引用了。URL.revokeObjectURL(href);element.remove();
};
關于前端下載文件的一些方法:https://blog.csdn.net/weixin_40119412/article/details/126980329
node 利用 excelJS 導出文件
//exportExcel\excel.js
// 導入
import ExcelJS from "exceljs";export default () => {// 創建工作薄const workbook = new ExcelJS.Workbook();// 設置工作簿屬性workbook.creator = "System";workbook.lastModifiedBy = "System";workbook.created = new Date(2024, 7, 3);workbook.modified = new Date();workbook.lastPrinted = new Date(2024, 7, 3);// 將工作簿日期設置為 1904 年日期系統workbook.properties.date1904 = true;// 在加載時強制工作簿計算屬性workbook.calcProperties.fullCalcOnLoad = true;workbook.views = [{x: 0,y: 0,width: 1000,height: 2000,firstSheet: 0,activeTab: 1,visibility: "visible",},];return workbook;
};
//exportExcel\index.js
import workbookFun from "./excel.js";export default async (data, columns, sheetName = "sheet1") => {const workbook = workbookFun();// 添加工作表const sheet = workbook.addWorksheet(sheetName);sheet.columns = columns;// 將數據添加到工作表中sheet.addRows(data);// 后端 node返回接口直接使用buffer流const bufferData = await workbook.xlsx.writeBuffer();// 瀏覽器可以利用Blob下載文件 ;node直接返回Blob會提示錯誤// const blob = new Blob([bufferData], {// type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'// });return bufferData;
};
利用 exceljs 庫和 buffer.Blob 返回數據出錯
原因 不支持返回 Blob 格式的數據,只支持字符串類型或 Buffer or Uint8Array
(Use `node --trace-warnings ...` to show where the warning was created)ErrorCaptureStackTrace(err);^TypeError [ERR_INVALID_ARG_TYPE]: The "chunk" argument must be of type string or an instance of Buffer or Uint8Array. Received an instance of Blob
MongoDB 操作
查看集合
show collections;
返回信息
user_table
role_table
刪除一個集合
db.user_table.drop();
創建一個集合
db.createCollection('template_table')
項目源碼在gitee:https://gitee.com/yanhsama/node-http-demo