一、开发接口
1.nodejs 处理 http 请求
http 请求概述
- DNS 解析,建立 TCP 连接,发送 http 请求
- server 接受到 http 请求,处理,并返回
- 客户端接受到返回数据,处理数据(如渲染页面,执行js)
nodejs 如何处理
get 请求 和 querystring
- get 请求,即客户端要向 server 端获取数据,如查询博客列表
- 通过 querystring 来传递数据,如a.html?a=100&b=200
- 浏览器直接访问,就发送 get 请求js
const http = require('http'); const querystring = require('querystring'); const server = http.createServer((req, res) => { console.log(req.method); const url = req.url; req.query = querystring.parse(url.split('?')[1]); // 解析 querystring res.end(JSON.stringify(req.query)); // 将 querystring 返回 }) server.listen(8000); // 然后浏览器访问 http://localhost:8000/
post 请求 和 postdata
- post 请求,即客户端要像服务端传递数据,如新建博客
- 通过 post data 传递数据
- 浏览器无法直接模拟,需要手写js,或者使用 postman等第三方工具js
const http = require('http'); const server = http.createServer((req, res) => { if (req.method === 'POST') { // 数据格式 console.log('content-type', req.headers['content-type']); let postData = ""; req.on('data', chunk => { postData += chunk.toString() }) req.on('end', () => { console.log(postData); res.end('hello world'); // 在这里返回,因为异步 }) } }) server.listen(8000); // 然后浏览器访问 http://localhost:8000/
路由
- nodejs 处理路由
- https://github.com/
- https://github.com/username
- https://github.com/username/xxxjs
const http = require('http'); const server = http.createServer((req, res) => { const url = req.url; const path = url.split('?')[0] res.end(path); // }) server.listen(8000); // 然后浏览器访问 http://localhost:8000/
- nodejs 处理路由
简单示例
jsconst http = require('http'); const server = http.createServer((req, res) => { res.end('hello world'); }) server.listen(8000); // 然后浏览器访问 http://localhost:8000/
综合示例
jsconst http = require('http'); const querystring = require('querystring'); const server = http.createServer((req, res) => { const method = req.method; const url = req.url; const path = url.split('?')[0]; const query = querystring.parse(url.split('?')[1]); // 设置返回格式 JSON res.setHeader('Content-type', 'application/json'); // 返回的数据 const resData = { method, url, path, query } // 返回 if (method === 'GET') { res.end(JSON.stringify(resData)) } if (method === 'POST') { let postData = ''; res.on('data', chunk => { postData += chunk.toString() }) res.on('end', () => { resData.postData = postData; // 返回 res.end(JSON.stringify(resData)) }) } }) server.listen(8000); // 然后浏览器访问 http://localhost:8000/
2.搭建开发环境
- 从0开始搭建,不使用任何框架
- 使用 nodemon 监测文件变化,自动重启 node
- 使用 cross-env 设置环境变量,兼容 mac linux 和 windows
- 搭建bolg1
- 相关命令shell
mkdir blog1 cd blog1 npm init -y touch bin/www.js touch app.js npm i nodemon -S npm i cross-env -S
- app.jsjs
const serverhandler = (req, res) => { // 设置返回格式 JSON res.setHeader('Content-type', 'application/json'); const resData = { name: '张三', site: 'baidu', env: process.env.NODE_ENV } res.end(JSON.stringify(resData)) } module.exports = serverhandler
- www.jsjs
const http = require('http'); const PORT = 8000; const serverhandler = require('../app'); const server = http.createServer(serverhandler); server.listen(PORT)
- package.jsonjson
{ "name": "blog1", "version": "1.0.0", "description": "", "main": "app.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "dev": "cross-env NODE_ENV=dev nodemon ./bin/www.js", "pro": "cross-env NODE_ENV=production nodemon ./bin/www.js" }, "keywords": [], "author": "", "license": "ISC", "dependencies": { "cross-env": "^7.0.3", "nodemon": "^2.0.15" } }
- 启动命令shell
npm run dev
- 相关命令
3.开发接口(暂不连接数据库,暂不考虑登录)
- 初始化路由:根据之前技术方案的设计,做出路由
- 返回假数据:将路由和数据处理分离,以符合设计原则
- 接口定义
- src/router/blog.jsjs
const handlerBlogRouter = (req, res) => { const {method, path } = req // 获取博客列表 if (method === 'GET' && path === '/api/blog/list') { return { msg: '这是获取博客列表的接口' } } // 获取博客详情 if (method === 'GET' && path === '/api/blog/detail') { return { msg: '这是获取博客详情的接口' } } // 新建一篇博客 if (method === 'POST' && path === '/api/blog/new') { return { msg: '这是新建博客的接口' } } // 更新一篇博客 if (method === 'POST' && path === '/api/blog/update') { return { msg: '这是更新博客的接口' } } // 删除一篇博客 if (method === 'POST' && path === '/api/blog/delete') { return { msg: '这是删除博客的接口' } } } module.exports = handlerBlogRouter
- src/router/user.jsjs
const handlerUserRouter = (req, res) => { const { method, path } = req // 登录 if (method === 'POST' && path === '/api/user/login') { return { msg: '这是登录接口' } } } module.exports = handlerUserRouter
- src/router/blog.js
- 开发路由
- 定义统一返回数据格式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 }
- 数据适配 [controller/blog.js]js
const getList = (author, keyword) => { // 先返回假数据 return [ { id: 1, title: '标题A', content: '内容A', createTime: 1649147318532, author: '张三' }, { id: 2, title: '标题B', content: '内容B', createTime: 1649147318533, author: '李四' } ] } module.exports = { getList }
- 路由应用[router/blog.js]js
const { getList } = require('../controller/blog'); const { SuccessModel } = require('../model/resModel'); const handlerBlogRouter = (req, res) => { const {method, path } = req // 获取博客列表 if (method === 'GET' && path === '/api/blog/list') { const author = req.query.author || ''; const keyword = req.query.keyword || ''; const listData = getList(author, keyword); return new SuccessModel(listData); } } module.exports = handlerBlogRouter
- post接口处理 getPostData /api/blog/newjs
const querystring = require('querystring'); const handlerBlogRouter = require('./src/router/blog'); const handlerUserRouter = require('./src/router/user'); // 用户处理 post data 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) => { // 设置返回格式 JSON res.setHeader('Content-type', 'application/json'); // 获取path const { url } = req; req.path = url.split('?')[0]; // 解析 query req.query = querystring.parse(url.split('?')[1]); // 处理 post data getPostData(req).then(postData => { req.body = postData; // 处理 blog 路由 const blogData = handlerBlogRouter(req, res); if (blogData) { res.end(JSON.stringify(blogData)); return } // 处理 user 路由 const userData = handlerUserRouter(req,res); if (userData) { res.end(JSON.stringify(userData)); return; } // 未命中路由,返回 404 res.writeHead(404, {"Content-type": "text/plain"}); res.write("404 Not Found\n"); res.end() }) } module.exports = serverhandler
- 定义统一返回数据格式