使用 live-server
Node.js 项目开发调试时前端项目时通常需要提供web服务器,才能实现一些页面的功能调试。
因为如果通过file://
协议访问html或js时,与相比 http://
协议安全方面差别较大,file://
访问文件时无法传递http协议头之类的东西,所以搭建web服务器成为了必须选项。
很多ide自动提供了这样的功能,如HBuilder. 自己搭建静态的web服务器也很容易,live-server这个node.js开发的软件就很好用。
live-server安装使用都很简单:
安装:
npm install -g live-server
使用:
live-server --port=9090
可以指定绑定的ip和端口号,也可以指定证书来配置对 https 协议的支持。live-server 能够自动监控文件变动从而自己重新加载页面,对前端开发来说非常方便。
搭建静态 Web 服务器
但也有一些情况下需要进行一些客户化设定,比如前后端分离项目,需要访问后端接口时,需要进行跨域的配置,如果使用代理方式的话,就可更加灵活的方式,而不必修改后端代码(因为这些修改常常是在正式发布后是不需要的,因为生产环境可能由网关完成跨域配置,或是同域的根本不需要跨域配置)。
这时自己能过简单的js文件完成一个代理的 web 服务器便很方便。
搭建一个可以访问静态文件的web服务器大体只需要以下的代码:
"use strict"; const fs = require('fs'); const path = require('path'); const http = require('http'); const url = require('url'); const PORT = 3000; const args = process.argv let staticBasePath = '../dist'; if(args.length>2) staticBasePath = args[2]; const staticServe = function(req, res) { const resolvedBase = path.resolve(staticBasePath); const safeSuffix = path.normalize(req.url).replace(/^(\.\.[\/\\])+/, ''); const fileLoc = path.join(resolvedBase, safeSuffix); let pathname = url.parse(req.url).pathname; //根据url得到文件路径,读取文件并返回给客户端 fs.readFile(fileLoc, function(err, data) { if (err) { res.writeHead(404, 'Not Found'); res.write('404: File Not Found!'); return res.end(); } res.statusCode = 200; res.write(data); return res.end(); }); }; const httpServer = http.createServer(staticServe); httpServer.listen(PORT);
fs, http, path, url都是node.js自带的模块,在以上简单的情况下,不需要安装额外的模块即可实现对js,html,css,图片的静态文件的访问。
搭建支持后端接口的代理服务器
当需要同时访问静态文件和后端接口时,可以增加对http-proxy的支持,只需要在上面代码的基础上增加少量代码如下:
"use strict"; const fs = require('fs'); const path = require('path'); const http = require('http'); const url = require('url'); const PORT = 3000; //npm install http-proxy --save-dev // 用来代理部分请求到java const httpProxy = require('http-proxy'); const proxy = httpProxy.createProxyServer({ //后端服务的接口地址 target: 'http://localhost:8080/', }); proxy.on('error', function(err, req, res){ res.writeHead(500, { 'content-type': 'text/plain' }); console.log(err); res.end('Something went wrong. And we are reporting a custom error message.'); }); const args = process.argv let staticBasePath = '../dist'; if(args.length>2) staticBasePath = args[2]; const staticServe = function(req, res) { const resolvedBase = path.resolve(staticBasePath); const safeSuffix = path.normalize(req.url).replace(/^(\.\.[\/\\])+/, ''); const fileLoc = path.join(resolvedBase, safeSuffix); let pathname = url.parse(req.url).pathname; //判断如果是接口访问,则通过proxy转发 //这里假设前端访问后端接口是通过 /gaming/xxx 来实现路由区分 if(pathname.indexOf("gaming") > 0){ proxy.web(req, res); return; } fs.readFile(fileLoc, function(err, data) { if (err) { res.writeHead(404, 'Not Found'); res.write('404: File Not Found!'); return res.end(); } res.statusCode = 200; res.write(data); return res.end(); }); }; const httpServer = http.createServer(staticServe); httpServer.listen(PORT);
Mime 类型的使用示例
如果需要对特殊文件的支持,如 WebAssembly, 扩展名是.wasm,则需要在返回的Content-Type上做一下处理,即:
var mime = require('mime') fs.readFile(fileLoc, function(err, data) { if (err) { res.writeHead(404, 'Not Found'); res.write('404: File Not Found!'); return res.end(); } let extension = path.extname(fileLoc); let type = mime.getType(fileLoc); if(type) { res.setHeader('Content-Type',type); }else if(extension=='.wasm'){ res.setHeader('content-type', "application/wasm"); } res.statusCode = 200; res.write(data); return res.end(); });
这是因为前端加载 WebAssembly 里,浏览器要求必须按application/wasm
返回 content-type.