http服务端有两种功能:
1. 提供静态服务 html /css 等
2. 提供动态数据服务
1. 浏览器请求示例
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> <!--服务器端不识别相对路径'../',默认/1.css--> <link href="../1.css" rel="stylesheet" /> </head> <body> <script> // 在5000端口下启动 const xhr = new XMLHttpRequest(); //PUT非简单请求;会发送OPTIONS请求 xhr.open('PUT', 'http://localhost:3000/userList', true); document.cookie = "token=20190993339" xhr.withCredentials = true; //跨域携带cookie xhr.responseType = 'application/json';// 非简单请求 xhr.onreadystatechange = function() { if(xhr.status === 200 && xhr.readyState === 4) { console.log(JSON.parse(xhr.response)); } } xhr.send(); </script> </body> </html>
2. 回调函数实现服务
let http = require('http'); let url = require('url'); let fs = require('fs'); let path = require('path'); // 上面都是核心内置模块 let mime = require('mime'); //第三方模块 // 回调函数实现服务 let server = http.createServer(function(req, res) { const { pathname } = url.parse(req.url); const method = req.method.toLowerCase(); //处理动态数据 switch(pathname) { case '/userList': if(method === 'get') { res.setHeader('Content-Type', 'application/json'); res.end(JSON.stringify({name: 'lyra'})); return; } } // 判断路径对应的是文件还是文件夹 let absolutePath = path.join(__dirname, pathname); fs.stat(absolutePath, function(err, statObj) { if(err) { res.statusCode = 404; res.end('Not Found'); return;// 结束 } if (statObj.isFile()) {// 是文件则直接读取返回对应路径下文件 const rs = fs.createReadStream(absolutePath); // 设置返回的响应头Content-Type res.setHeader('Content-Type', mime.getType(absolutePath)+";charset=utf-8"); rs.pipe(res); //包含 res.end(...)逻辑 } else {// 是文件夹;默认查找index.html const indexPath = path.join(absolutePath, 'index.html'); fs.access(indexPath, function(err) { if(err) { res.statusCode = 404; res.end('Not Found'); return;// 结束 } res.setHeader('Content-Type', 'text/html;charset=utf-8');// utf-8中间要有间隔符,IE兼容 fs.createReadStream(indexPath).pipe(res); }) } }) }); server.listen(3000);
3. aysnc...await封装
使用第三方的mz/fs模块,该模块下文件处理Promise化。
let http = require('http'); let url = require('url'); let fs = require('mz/fs'); let path = require('path'); // 上面都是核心内置模块 let mime = require('mime'); //第三方模块 class Server { constructor() { this.handleRequest = this.handleRequest.bind(this); } async handleRequest(req, res) { const { pathname } = url.parse(req.url, true); //处理动态数据 this.handleDataRequest(pathname,req, res); const absPath = path.join(__dirname, pathname); try { // 处理静态文件 let statObj = await fs.stat(absPath); if (statObj.isFile()) { this.sendFile(res, absPath); } else { const realpath = path.join(absPath, 'index.html'); await fs.access(realpath); this.sendFile(res, realpath); } } catch(e) { console.log(e); this.sendError(res); } } handleDataRequest(dataPath,req, res) { const method = req.method.toLowerCase(); /*************************跨域的通用解决方案***********************************/ res.setHeader('Access-Control-Allow-Origin', 'http://localhost:5000'); res.setHeader('Access-Control-Allow-Credentials', true); res.setHeader('Access-Control-Allow-Methods', 'PUT,DELETE,POST,GET,OPTIONS,HEAD'); res.setHeader('Access-Control-Allow-Headers', "Content-Type"); res.setHeader('Access-Control-Max-Age', 10000); //s // options请求不做处理 if(method === 'options') { res.end();// 可访问 } /****************************************************************************/ //处理动态数据 switch(dataPath) { case '/userList': if(method === 'get') { res.setHeader('Content-Type', 'application/json'); res.end(JSON.stringify({name: 'lyra'})); } if(method === 'put') { } } } sendFile(res, realpath) { res.setHeader('Content-Type', mime.getType(realpath)+";charset=utf-8") fs.createReadStream(realpath).pipe(res); } sendError(res) { res.statusCode = 404; res.end('Not Found'); return; } start(port) { let server = http.createServer(this.handleRequest); server.listen(port); } } let server = new Server(); server.start(3000);