import * as fs from 'fs';
// 回调函数一般是异步的
// 文件操作一般都是错误优先回调函数
fs.mkdir('made-by-fs', err => {
if (err) console.log('文件夹已经存在');
else console.log('文件夹创建成功');
})
fs.rename('./made-by-fs', './log', err=>{
if (err) console.log('文件夹名字已经存在');
else console.log('文件夹名字修改成功');
})
fs.rmdir('./log', err => {
console.log(err);
})
// 错误优先回调函数
fs.readdir('./logs', ((err, files) => {
console.log(files);
}))
// 写文件
fs.writeFile('./logs/log1.txt', 'hello\nworld', err => {
console.log(err);
})
// 追加文本
fs.appendFile('./logs/log1.txt', '!!!', err => {
console.log(err);
})
// 判断文件是否存在
fs.exists('./logs/log', exists => {
console.log(exists);
})
// 删除文件
fs.unlink('./logs/log1.txt', err => {
console.log(err);
})
// 读取文件
fs.readFile('./logs/log1.txt','utf-8', (err, data) => {
console.log(data);
})
fs.readFile('./logs/log1.txt', (err, data) => {
console.log(data.toString());
})
// 每一个都添加了一个sync表示同步代码
const fileHandleData = fs.readFileSync('./log/log1.txt', 'utf-8');
console.log(fileHandleData);
// 基于promise的文件读取
const promiseFs = require('fs').promise;
async function main_read_file(){
const data = await promiseFs.readFile('./logs/log1.txt');
console.log(data);
}
main_read_file();
import * as fs from 'fs';
// 循环创建文件
for (let i = 0; i < 3; i++) {
fs.writeFile('./log' + i + '.txt', 'log-' + i, 'utf-8', () => {
console.log(`第${i}次创建成功!`);
});
}
// 遍历文件夹
fs.readdir('./', 'utf-8', (err, files) => {
console.log(files);
// [ 'app.js', 'fs_test.js', 'log', 'log.txt', 'practice.js' ]
files.forEach((value, index) => {
// 读取文件或者文件夹,判断当前读取的是哪一种类型
fs.stat('./' + value, (err1, stats) => {
if (stats.isDirectory()) {
// 这里可以调用递归
console.log('文件夹', value);
} else {
// 如果是一个文件的话,那么就读取这个文件
console.log('文件', value);
}
})
})
})
// 监视watch,与监视文件
fs.watch('./log/log.log', 'utf-8', (eventType, filename) => {
console.log('文件被修改了');
})
fs.watchFile('./log.txt', ((curr, prev) => {
console.log(curr, prev);
}))
import * as fs from 'fs';
import * as zlib from 'zlib';
// 将文件变成压缩包
const gzip = zlib.createGzip();
const readStream = fs.createReadStream('./logs.txt');
const writeStream = fs.createWriteStream('./logs.gzip');
readStream.pipe(gzip).pipe(writeStream);
// in test1.js 文件
import {a, b, c, sayHello} from './test2.js';
console.log(a, b, c);
sayHello();
// in test2.js 文件
export let a = 1;
let b = 10;
let c = 20;
export {b, c};
export function sayHello(){
console.log('hello');
}
// 表示默认暴露一个
// export default a;
// test1.js
const {b, c, sayHello} = require('./test2')
console.log(b, c);
sayHello();
// test2.js
let b = 10;
let c = 20;
function sayHello(){
console.log('hello');
}
// 表示默认暴露一个
// export default a;
module.exports.b = b;
module.exports.c = c;
module.exports.sayHello = sayHello;
// url.parse(urlString[, parseQueryString[, slashesDenoteHost]])
const url = require('url')
const urlString = 'https://www.baidu.com:443/ad/index.html?id=8&name=mouse#tag=110'
const parsedStr = url.parse(urlString)
console.log(parsedStr)
// url.format(urlObject)
const url = require('url')
const urlObject = {
protocol: 'https:',
slashes: true,
auth: null,
host: 'www.baidu.com:443',
port: '443',
hostname: 'www.baidu.com',
hash: '#tag=110',
search: '?id=8&name=mouse',
query: { id: '8', name: 'mouse' },
pathname: '/ad/index.html',
path: '/ad/index.html?id=8&name=mouse',
href: 'https://www.baidu.com:443/ad/index.html?id=8&name=mouse#tag=110'
}
const parsedObj = url.format(urlObject)
console.log(parsedObj)
// url.resolve(from, to)
const url = require('url')
var a = url.resolve('/one/two/three', 'four')
var b = url.resolve('http://example.com/', '/one')
var c = url.resolve('http://example.com/one', '/two')
console.log(a + "," + b + "," + c)
// querystring.parse(str[, sep[, eq[, options]]])
const querystring = require('querystring')
var qs = 'x=3&y=4'
var parsed = querystring.parse(qs)
console.log(parsed)
// [Object: null prototype] { x: '3', y: '4' }
// querystring.stringify(obj[, sep[, eq[, options]]])
const querystring = require('querystring')
var qo = {
x: 3,
y: 4
}
var parsed = querystring.stringify(qo)
console.log(parsed)
// x=3&y=4
// escape
const querystring = require('querystring')
var str = 'id=3&city=北京&url=https://www.baidu.com'
var escaped = querystring.escape(str)
console.log(escaped)
// id%3D3%26city%3D%E5%8C%97%E4%BA%AC%26url%3Dhttps%3A%2F%2Fwww.baidu.com
// /unescape
const querystring = require('querystring')
var str = 'id%3D3%26city%3D%E5%8C%97%E4%BA%AC%26url%3Dhttps%3A%2F%2Fwww.baidu.com'
var unescaped = querystring.unescape(str)
console.log(unescaped)
// id=3&city=北京&url=https://www.baidu.com
Title
import * as http from 'http';
const server = http.createServer((req, res) => {
let url = req.url;
switch (url) {
// 所谓的反向代理,就是将
case '/api/data': {
res.writeHead(200, {
'content-type': 'application/json',
// 设置这个表示可以跨域,或者说我可以把数据给任何想要我的数据的请求
'Access-Control-Allow-Origin': '*',
});
res.write(JSON.stringify({id: 12, name: 'alex'}));
break;
}
default: {
res.write('page not found');
break;
}
}
res.end();
})
server.listen(8080, () => {
console.log('http://localhost:8080');
})
当尝试通过浏览器从一个源请求到其他的源时,会发生跨域请求行为,此时这个请求开始是可以发出去的,但是当服务端没有做跨域处理时,浏览器是不承认该数据是合法的,所以在返回数据的请求头里面加入以下元素:Access-Control-Allow-Origin': '*',可以解决,表是给任何想要向我请求数据的客户端,当然也可以实现白名单来实现指定源来访问。
Jsonp
import * as http from 'http';
const server = http.createServer((req, res) => {
let url = req.url;
console.log(url);
// 如果是携带了参数的get请求,那么url就是 /path/to/script?callback=getData
// 然后将url解析为query字符以及path请求路径,根据查询字符窜拼接script,然后就会将script返回给前端
// 前端识别到这个函数之后就会执行,也就是通过get请求携带回调函数名称来实现加载调用
// 类似于这种方式就是jsonp跨域,但不一定一定要回调函数参数
switch (url){
case '/api/data':{
res.write('alert(\'hello\'):getData(\'hello\')');
break;
}
default:{
res.write('page not found');
break;
}
}
res.end();
})
server.listen(8080, ()=>{
console.log('http://localhost:8080');
})
jsonp实现跨域请求的方式就是指定scrpt标签里面的scr的属性来实现跨域,著名的引用就是cdn
// npm install http-proxy-middleware, 下载中间键
import * as proxyMiddleware from 'http-proxy-middleware';
import * as http from 'http';
const server = http.createServer((req, res) => {
const url = req.url;
// 当访问到我的请求之后,服务器就会执行代理,
// 所谓的代理就是将ajax以后的请求数据不变,然后将起始前面的域名更改
// 实现服务器帮我转发请求,服务器拿到数据之后,返回给我的请求,这个就是正向代理
// 我在浏览器里面输入 http://localhost:8080/ajax?id=name&age=18
// 实际请求的网址是 https://lady.vip.com/ajax?id=name&age=18
// 然后将实际请求完成之后的数据发给我请求的网址
if (/^\/ajax/.test(url)){
// https://lady.vip.com/ajax, ajax; 上下文接口起始名称
let proxy = proxyMiddleware.createProxyMiddleware('/ajax', {
target: 'https://lady.vip.com',
changeOrigin: true
})
proxy(req, res);
}else {
console.log('not a proxy');
}
})
server.listen(8080, ()=>{
console.log('http://localhost:8080');
})
既然浏览器有同源策略的限制,那么就从服务器那边实现请求,这样就不会有限制,通过这种方式实现的跨域请求就是代理。
var http = require('http')
var https = require('https')
// 1、接口 2、跨域
const server = http.createServer((request, response) => {
var url = request.url.substr(1)
var data = ''
response.writeHeader(200, {
'content-type': 'application/json;charset=utf-8',
'Access-Control-Allow-Origin': '*'
})
https.get(`https://m.lagou.com/listmore.json${url}`, (res) => {
res.on('data', (chunk) => {
data += chunk
})
res.on('end', () => {
response.end(JSON.stringify({
ret: true,
data
}))
})
})
})
server.listen(8080, () => {
console.log('localhost:8080')
})
const https = require('https')
const querystring = require('querystring')
const postData = querystring.stringify({
province: '上海',
city: '上海',
district: '宝山区',
address: '同济支路199号智慧七立方3号楼2-4层',
latitude: 43.0,
longitude: 160.0,
message: '求购一条小鱼',
contact: '13666666',
type: 'sell',
time: 1571217561
})
const options = {
protocol: 'https:',
hostname: 'ik9hkddr.qcloud.la',
method: 'POST',
port: 443,
path: '/index.php/trade/add_item',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': Buffer.byteLength(postData)
}
}
function doPost() {
let data
let req = https.request(options, (res) => {
res.on('data', chunk => data += chunk)
res.on('end', () => {
console.log(data)
})
})
req.write(postData)
req.end()
}
// setInterval(() => {
// doPost()
// }, 1000)
import * as http from 'http';
import * as querystring from 'querystring';
const server = http.createServer((req, res) => {
// 获取请求地址
const url = req.url;
// console.log(url); // --> /
let data = '';
req.on('data', chunk => {
data += chunk;
// 如果是post请求:并且是原生表单的形式 x-www-form-urlencoded, 提交的数据
// 那么返回的形式为 data = id=33&name=tom
})
req.on('end', () => {
console.log(JSON.stringify(querystring.parse(data)));
// {"id":"33","name":"tom"}
// 返回数据, 返回的状态码只是一个数字而已,具体返回什么还是要看自己
res.writeHead(200, {
'content-type': 'application/json;charset=utf8'
// text/plain : 表示的就是一个纯文本,
// application/json;charset=utf8 : 表示json
// text/html : 表示html
});
// 将数据发送给前端
res.write(JSON.stringify({x: url}));
res.end();
})
})
server.listen(8080, () => {
console.log('http://localhost:8080');
})
// node 浏览器调试模式
// node --inspect --inspect-brk 文件名.js
// node 进程管理工具
// supervisor
// nodemon
// forever
// pm2
// 注意,必须是指定被执行文件的路径,下执行才会有效
// 当代码改变时,会从新启动服务器
// Usage: nodemon [options] [script.js] [args]
// 这里用的是nodemon, 安装完成之后执行命令 nodemon 文件名.js
// 然后就会监视进程
此时用到的模块为nodemon,是专门监视文件变化的一个第三方模块,当文件变化时,会重新启动文件服务,用法:odemon server.js;
import * as http from 'http';
import * as https from 'https';
// 下载cheerio, 可以将text/plain/转化为虚拟html,dom
import * as cheerio from 'cheerio';
function filterData(data){
const $ = cheerio.load(data);
$('.section-item-box p').each((index, ele)=>{
console.log($(ele).text());
})
}
const server = http.createServer((req, res) => {
let data = '';
https.get('https://www.meizu.com', result=>{
// 拿到数据
result.on('data', chunk=>{
data += chunk;
})
// 分析数据, 这里拿到的是一个html文本文档
result.on('end', ()=>{
filterData(data);
})
})
})
server.listen(8080, ()=>{
console.log('http://localhost:8080')
})
import * as events from 'events';
class MyEventEmitter extends events.EventEmitter {
}
const event = new MyEventEmitter();
// 绑定事件
event.on('play', value=>{
console.log(value);
})
// 执行事件, 每一个事件可以从重复定义,然后提交一次就会执行两次
event.emit('play', 'movie');
import * as readline from 'readline';
// readline 逐行读写
// 用于控制台输入输出
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
rl.question('你好啊,好啊?', answer => {
console.log('thanks for your:' + answer);
rl.close();
})
import * as crypto from 'crypto';
const password = '1234alex';
const hash = crypto
// 指定加密方式
.createHash('sha1')
// 指定加密的字符与编码格式
.update(password, 'utf-8')
// 指定编码之后的输出类型,这里时十六进制
.digest('hex');
console.log(hash);
文件目录树:在windows下输出目录树有两种方式,第一种执行‘tree'返回的是该目录下的所有的文件夹树结构,如果是'tree /f'表示输出包括扩展名的文件,如果再在后面添加’>tree.txt'表示输出到当前目录的tree.txt文件,如果没有的话就会创建,完整的输入为'tree /f >tree.txt';
// 文件的目录树结构
D:.
│ fileStatic.js
│ server.js
│ tree.txt
│
└─public
│ index.html
│
├─css
│ index.css
│
├─imgs
│ img.png
│
└─script
common.js
fileStatic.js
import * as path from 'path';
// 获取文件的类型,例如 .txt 返回的是 text/plain
export function readStaticFile(staticFilePath, fileHandle) {
let ext = path.parse(staticFilePath).ext;
// 这里自己写一个
let map = new Map([
['.html', 'text/html'],
['.txt', 'text/plain'],
['.js', 'application/x-javascript'],
['.css', 'text/css'],
['.png', 'image/png']]);
// 如果是一个文件的话
if (map.has(ext)){
// 如果是文件类型但是又不是文件
try {
return [fileHandle.readFileSync(staticFilePath), map.get(ext)];
}catch (e){
return ['404 Not Found File
', map.get('.html')];
}
}else {
// 如果不是文件类型但是又是一个文件夹
try {
return [fileHandle.readFileSync(path.join(staticFilePath, 'index.html')), map.get('.html')];
}catch (e){
return ['404 Not Found File
', map.get('.html')];
}
}
}
server.js
import * as http from 'http';
import * as path from 'path';
import {readStaticFile} from "./fileStatic.js";
import * as fs from 'fs';
const server = http.createServer((req, res) => {
let urlString = req.url;
// 返回的是一个跟路径,就是 当前文件的目录
const __dirname = path.resolve();
// 拼接文件路径
const publicFilePath = path.join(__dirname, 'public', urlString);
// 判断当前是否存在路径
if (fs.existsSync(publicFilePath)){
let [fileData, fileType] = readStaticFile(publicFilePath, fs);
res.writeHead(200, {
'content-type': fileType
})
res.write(fileData);
res.end();
}else {
res.write('nono');
}
res.end();
})
server.listen(8080, ()=>{
console.log('http://localhost:8080');
// http://localhost:8080, 之后的都算是url路径
})
index.html
Title
hello world
在自己的文件下 ./ 表示当前文件所在的路径, 在网站中, .\表示域名下的路径
例如,自己文件夹写的是:./script/common.js
实际请求中:http://localhost:8080/script/common.js
common.js ---> 里面什么都没有
index.css ---> 随便写的一个样式
h3{
background-color: pink;
}
var express = require('express');
var app = express();
app.get('/', function (req, res) {
res.send('Hello World!');
});
var server = app.listen(3000, function () {
var host = server.address().address;
var port = server.address().port;
console.log('Example app listening at http://%s:%s', host, port);
});
// GET method route
// 对网站首页的访问返回 "Hello World!" 字样
app.get('/', function (req, res) {
res.send('Hello World!')
})
// 网站首页接受 POST 请求
app.post('/', function (req, res) {
res.send('Got a POST request')
})
// /user 节点接受 PUT 请求
app.put('/user', function (req, res) {
res.send('Got a PUT request at /user')
})
// /user 节点接受 DELETE 请求
app.delete('/user', function (req, res) {
res.send('Got a DELETE request at /user')
})
/*
app.all() 是一个特殊的路由方法,没有任何 HTTP 方法与其对应,它的作用是对于一个路径上的所有请求加载中间件。
*/
app.all('/secret', function (req, res, next) {
console.log('Accessing the secret section ...')
next(); // pass control to the next handler
})
// 匹配根路径的请求
app.get('/', function (req, res) {
res.send('root');
});
// 匹配 /about 路径的请求
app.get('/about', function (req, res) {
res.send('about');
});
// 匹配 /random.text 路径的请求
app.get('/random.text', function (req, res) {
res.send('random.text');
});
// 匹配 acd 和 abcd
app.get('/ab?cd', function(req, res) {
res.send('ab?cd');
});
// 匹配 abcd、abbcd、abbbcd等
app.get('/ab+cd', function(req, res) {
res.send('ab+cd');
});
// 匹配 abcd、abxcd、abRABDOMcd、ab123cd等
app.get('/ab*cd', function(req, res) {
res.send('ab*cd');
});
// 匹配 /abe 和 /abcde
app.get('/ab(cd)?e', function(req, res) {
res.send('ab(cd)?e');
});
// 匹配任何路径中含有 a 的路径:
app.get(/a/, function(req, res) {
res.send('/a/');
});
// 匹配 butterfly、dragonfly,不匹配 butterflyman、dragonfly man等
app.get(/.*fly$/, function(req, res) {
res.send('/.*fly$/');
});
// 使用一个回调函数处理路由:
app.get('/example/a', function (req, res) {
res.send('Hello from A!');
});
// 使用多个回调函数处理路由(记得指定 next 对象):
app.get('/example/b', function (req, res, next) {
console.log('response will be sent by the next function ...');
next();
}, function (req, res) {
res.send('Hello from B!');
});
// 使用回调函数数组处理路由:
var cb0 = function (req, res, next) {
console.log('CB0')
next()
}
var cb1 = function (req, res, next) {
console.log('CB1')
next()
}
var cb2 = function (req, res) {
res.send('Hello from C!')
}
app.get('/example/c', [cb0, cb1, cb2])
// 混合使用函数和函数数组处理路由:
var cb0 = function (req, res, next) {
console.log('CB0')
next()
}
var cb1 = function (req, res, next) {
console.log('CB1')
next()
}
app.get('/example/d', [cb0, cb1], function (req, res, next) {
console.log('response will be sent by the next function ...')
next()
}, function (req, res) {
res.send('Hello from D!')
})
res.download() 提示下载文件。
res.end() 终结响应处理流程。
res.json() 发送一个 JSON 格式的响应。
res.jsonp() 发送一个支持 JSONP 的 JSON 格式的响应。
res.redirect() 重定向请求。
res.render() 渲染视图模板。
res.send() 发送各种类型的响应。
res.sendFile 以八位字节流的形式发送文件。
res.sendStatus() 设置响应状态代码,并将其以字符串形式作为响应体的一部分发送。
var express = require('express');
var router = express.Router();
// 该路由使用的中间件
router.use(function timeLog(req, res, next) {
console.log('Time: ', Date.now());
next();
});
// 定义网站主页的路由
router.get('/', function(req, res) {
res.send('Birds home page');
});
// 定义 about 页面的路由
router.get('/about', function(req, res) {
res.send('About birds');
});
module.exports = router;
var birds = require('./birds')
...
app.use('/birds', birds)
// 应用即可处理发自 /birds 和 /birds/about 的请求,并且调用为该路由指定的 timeLog 中间件。
/*
将静态资源文件所在的目录作为参数传递给 express.static 中间件
就可以提供静态资源文件的访问了。例如,假设在 public 目录放置了
图片、CSS 和 JavaScript 文件,你就可以:
*/
app.use(express.static('public'))
/*
http://localhost:3000/images/kitten.jpg
http://localhost:3000/css/style.css
http://localhost:3000/js/app.js
http://localhost:3000/images/bg.png
http://localhost:3000/hello.html
*/
// 如果你的静态资源存放在多个目录下面,你可以多次调用 express.static 中间件:
app.use(express.static('public'))
app.use(express.static('files'))
/*
如果你希望所有通过 express.static 访问的文件都存放
在一个“虚拟(virtual)”目录(即目录根本不存在)下面,
可以通过为静态资源目录指定一个挂载路径的方式来实现,如下所示:
*/
app.use('/static', express.static('public'))
/*
http://localhost:3000/static/images/kitten.jpg
http://localhost:3000/static/css/style.css
http://localhost:3000/static/js/app.js
http://localhost:3000/static/images/bg.png
http://localhost:3000/static/hello.html
*/
应用级中间件绑定到 app 对象 使用 app.use() 和 app.METHOD(), 其中, METHOD 是需要处理的 HTTP 请求的方法,例如 GET, PUT, POST 等等,全部小写。例如:
var app = express()
// 没有挂载路径的中间件,应用的每个请求都会执行该中间件
app.use(function (req, res, next) {
console.log('Time:', Date.now())
next()
})
// 挂载至 /user/:id 的中间件,任何指向 /user/:id 的请求都会执行它
app.use('/user/:id', function (req, res, next) {
console.log('Request Type:', req.method)
next()
})
// 路由和句柄函数(中间件系统),处理指向 /user/:id 的 GET 请求
app.get('/user/:id', function (req, res, next) {
res.send('USER')
})
下面这个例子展示了在一个挂载点装载一组中间件。
// 一个中间件栈,对任何指向 /user/:id 的 HTTP 请求打印出相关信息
app.use('/user/:id', function(req, res, next) {
console.log('Request URL:', req.originalUrl)
next()
}, function (req, res, next) {
console.log('Request Type:', req.method)
next()
})
作为中间件系统的路由句柄,使得为路径定义多个路由成为可能。在下面的例子中,为指向 /user/:id 的 GET 请求定义了两个路由。第二个路由虽然不会带来任何问题,但却永远不会被调用,因为第一个路由已经终止了请求-响应循环。
// 一个中间件栈,处理指向 /user/:id 的 GET 请求
app.get('/user/:id', function (req, res, next) {
console.log('ID:', req.params.id)
next()
}, function (req, res, next) {
res.send('User Info')
})
// 处理 /user/:id, 打印出用户 id
app.get('/user/:id', function (req, res, next) {
res.end(req.params.id)
})
如果需要在中间件栈中跳过剩余中间件,调用 next('route') 方法将控制权交给下一个路由。 注意: next('route') 只对使用 app.VERB() 或 router.VERB() 加载的中间件有效。
// 一个中间件栈,处理指向 /user/:id 的 GET 请求
app.get('/user/:id', function (req, res, next) {
// 如果 user id 为 0, 跳到下一个路由
if (req.params.id == 0) next('route')
// 否则将控制权交给栈中下一个中间件
else next() //
}, function (req, res, next) {
// 渲染常规页面
res.render('regular')
});
// 处理 /user/:id, 渲染一个特殊页面
app.get('/user/:id', function (req, res, next) {
res.render('special')
})
路由级中间件和应用级中间件一样,只是它绑定的对象为 express.Router()。
var router = express.Router()
路由级使用 router.use() 或 router.VERB() 加载。
上述在应用级创建的中间件系统,可通过如下代码改写为路由级:
var app = express()
var router = express.Router()
// 没有挂载路径的中间件,通过该路由的每个请求都会执行该中间件
router.use(function (req, res, next) {
console.log('Time:', Date.now())
next()
})
// 一个中间件栈,显示任何指向 /user/:id 的 HTTP 请求的信息
router.use('/user/:id', function(req, res, next) {
console.log('Request URL:', req.originalUrl)
next()
}, function (req, res, next) {
console.log('Request Type:', req.method)
next()
})
// 一个中间件栈,处理指向 /user/:id 的 GET 请求
router.get('/user/:id', function (req, res, next) {
// 如果 user id 为 0, 跳到下一个路由
if (req.params.id == 0) next('route')
// 负责将控制权交给栈中下一个中间件
else next() //
}, function (req, res, next) {
// 渲染常规页面
res.render('regular')
})
// 处理 /user/:id, 渲染一个特殊页面
router.get('/user/:id', function (req, res, next) {
console.log(req.params.id)
res.render('special')
})
// 将路由挂载至应用
app.use('/', router)
错误处理中间件有 4 个参数,定义错误处理中间件时必须使用这 4 个参数。
即使不需要 next 对象,也必须在签名中声明它,否则中间件会被识别为一
个常规中间件,不能处理错误。
错误处理中间件和其他中间件定义类似,只是要使用 4 个参数,而不是 3 个,
其签名如下: (err, req, res, next)。
app.use(function(err, req, res, next) {
console.error(err.stack)
res.status(500).send('Something broke!')
})
/*
从 4.x 版本开始,, Express 已经不再依赖 Connect 了。除了 express.static,
Express 以前内置的中间件现在已经全部单独作为模块安装使用了。请参考 中间件列表。
express.static(root, [options])
express.static 是 Express 唯一内置的中间件。它基于 serve-static,负责在 Express
应用中提托管静态资源。
参数 root 指提供静态资源的根目录。
可选的 options 参数拥有如下属性。
属性 描述 类型 缺省值
dotfiles 是否对外输出文件名以点(.)开头的文件。可选值为 “allow”、
“deny” 和 “ignore” String “ignore”
etag 是否启用 etag 生成 Boolean true
extensions 设置文件扩展名备份选项 Array []
index 发送目录索引文件,设置为 false 禁用目录索引。 Mixed “index.html”
lastModified 设置 Last-Modified 头为文件在操作系统上的最后修改日期。
可能值为 true 或 false。 Boolean true
maxAge 以毫秒或者其字符串格式设置 Cache-Control 头的 max-age 属性。 Number 0
redirect 当路径为目录时,重定向至 “/”。 Boolean true
setHeaders 设置 HTTP 头以提供文件的函数。 Function
*/
var options = {
dotfiles: 'ignore',
etag: false,
extensions: ['htm', 'html'],
index: false,
maxAge: '1d',
redirect: false,
setHeaders: function (res, path, stat) {
res.set('x-timestamp', Date.now())
}
}
app.use(express.static('public', options))
需要在应用中进行如下设置才能让 Express 渲染模板文件:
views, 放模板文件的目录,比如: app.set('views', './views')
view engine, 模板引擎,比如: app.set('view engine', 'ejs')
1、Install
npm install --save art-template
npm install --save express-art-template
2、Example
var express = require('express')
var app = express()
// view engine setup
app.engine('art', require('express-art-template'))
app.set('view', {
debug: process.env.NODE_ENV !== 'production'
})
app.set('views', path.join(__dirname, 'views'))
app.set('view engine', 'art')
// routes
app.get('/', function (req, res) {
res.render('index.art', {
user: {
name: 'aui',
tags: ['art', 'template', 'nodejs']
}
})
})
const express = require('express');
const body_parser = require('body-parser');
const art_template = require('express-art-template');
const path = require('path');
const app = express();
const router = require('./router/index.js');
// 这里可以通过使用body-parser 来解析 post 中的 req.body,
// 专门用来解析 application/x-www-form-urlencoded 发送的表单数据
app.use(body_parser.urlencoded({extended: false}));
// 解析json字符窜
app.use(body_parser.json());
// app.use((req, res, next) => {
// // do something here
// // 默认匹配 为 *
// })
// 配置静态资源中间键, 内置中间件
app.use(express.static('./public'));
// npm i art-template express-art-template
// 配置模板渲染引擎, view和views都是默认的key
app.engine('html', art_template);
// 设置配置环境
app.set('view options', {
debug: process.env.NODE_ENV !== 'production'
})
// 设置模板引擎寻找文件的路径
app.set('views', path.join(__dirname, 'template'));
// 下面的第二个参数 art 为 template 模板下的扩展名
app.set('view engine', 'html');
// 可以使用多个初级路由筛选器,类似于python中的include urls
app.use('/', router);
app.listen(8080, () => {
console.log('http://localhost:8080');
})
const jwt = require('jsonwebtoken');
const fs = require("fs");
let payLoad = {data: 'this is a data'};
let privateKey = fs.readFileSync('./key/rsa_private_key.pem', 'utf-8');
const token = jwt.sign(payLoad, privateKey, {algorithm:'RS256'});
// console.log(token)
let publicKey = fs.readFileSync('./key/rsa_public_key.pem', 'utf-8');
let res = jwt.verify(token, publicKey, {algorithm: 'RS256'});
console.log(res);
client.js
const net = require('net');
const client = net.createConnection({port: 6527}, ()=>{
console.log('connected to server');
client.write('world!\r\n');
})
client.on('data', data => {
console.log(data.toString());
client.end();
})
client.on('end', ()=>{
console.log('disconnected from server');
})
server.js
const net = require('net');
const server = net.createServer(socket => {
socket.write('hello world\r\n');
})
server.on('data', (data)=>{
console.log(data.toString());
})
server.on('error', err=>{
console.log(err);
})
server.listen('6527',()=>{
console.log(server.address())
})
client.js
const net = require('net');
const readline = require('readline');
let port = 8080;
let host = 'localhost';
let socket = new net.Socket();
socket.setEncoding('utf-8');
socket.connect(port, host, ()=>{
socket.write('hello');
say();
})
socket.on('data', data=>{
console.log(data.toString());
})
// 用于控制台输入输出
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
function say(){
rl.question('请输入:\n', answer => {
if (answer !== 'bye'){
socket.write(answer + '\n');
}else {
socket.destroy();
rl.close();
}
})
}
server.js
const net = require('net');
const server = new net.createServer();
let clients = {};
let clientName = 0;
function broadcast(socket, data){
for (let client in clients){
// 聊天室
// 相当于给群里的每一个人都发一次消息,
clients[client].write(socket.name + '说:' + data);
}
}
server.on('connection', socket => {
// 将创建的连接保存到数组
socket.name = ++clientName;
clients[socket.name] = socket;
// 绑定事件
socket.on('data', data => {
broadcast(socket, data.toString());
})
socket.on('error', err => {
console.log('client error' + err);
socket.end();
})
socket.on('close', hadError => {
delete clients[clients.name];
console.log(socket.name + '下线了');
})
})
server.listen({host: 'localhost', port:8080}, ()=>{
console.log('服务器端已经启动');
})
目录树
D:.
│ fileStatic.js
│ server.js
│ socketServer.js
│ tree.txt
│
└─public
│ index.html
│
├─css
│ index.css
│
├─imgs
│ img.png
│
└─script
WsClient.js
fileStatic.js
const path = require('path');
// 获取文件的类型,例如 .txt 返回的是 text/plain
function readStaticFile(staticFilePath, fileHandle) {
let ext = path.parse(staticFilePath).ext;
// 这里自己写一个
let map = new Map([
['.html', 'text/html'],
['.txt', 'text/plain'],
['.js', 'application/x-javascript'],
['.css', 'text/css'],
['.png', 'image/png']]);
// 如果是一个文件的话
if (map.has(ext)){
// 如果是文件类型但是又不是文件
try {
return [fileHandle.readFileSync(staticFilePath), map.get(ext)];
}catch (e){
return ['404 Not Found File
', map.get('.html')];
}
}else {
// 如果不是文件类型但是又是一个文件夹
try {
return [fileHandle.readFileSync(path.join(staticFilePath, 'index.html')), map.get('.html')];
}catch (e){
return ['404 Not Found File
', map.get('.html')];
}
}
}
exports.readStaticFile = readStaticFile;
server.js
const http = require('http');
const path = require('path');
const {readStaticFile} = require('./fileStatic.js');
const fs = require('fs');
const server = http.createServer((req, res) => {
let urlString = req.url;
// 返回的是一个跟路径,就是 当前文件的目录
const __dirname = path.resolve();
// 拼接文件路径
const publicFilePath = path.join(__dirname, 'public', urlString);
// 判断当前是否存在路径
if (fs.existsSync(publicFilePath)){
let [fileData, fileType] = readStaticFile(publicFilePath, fs);
res.writeHead(200, {
'content-type': fileType
})
res.write(fileData);
res.end();
}else {
res.write('nono');
}
res.end();
})
server.listen(8080, ()=>{
console.log('http://localhost:8080');
// http://localhost:8080, 之后的都算是url路径
})
socketServer.js
// 下载 ws 包,npm i ws
const websocket = require('ws');
const wss = new websocket.Server({port:8000});
wss.on('connection', function connection(ws){
ws.on('open', function close(){
console.log('connected !!!');
ws.send('hello');
})
ws.on('message', function incoming(data){
wss.clients.forEach(function each(client){
client.send(data.toString());
})
})
ws.on('close', function close(){
console.log('disconnected !!!');
})
})
index.html
WebSocket
交流区
index.css
h3{
background-color: pink;
}
D:.
index.html
socketServer.js
index.html
Socket.IO chat
socketServer.js
const express = require("express");
const {createServer} = require("http");
const {Server} = require("socket.io");
const app = express();
const httpServer = createServer(app);
const io = new Server(httpServer, { /* options */});
app.get('/', (req, res) => {
res.sendFile(__dirname + '/index.html');
});
io.on('connection', (socket) => {
socket.broadcast.emit('hi');
});
io.on('connection', (socket) => {
console.log('a user connected');
socket.on('disconnect', () => {
console.log('user disconnected');
});
});
io.on('connection', (socket) => {
socket.on('chat message', (msg) => {
console.log('message: ' + msg);
});
});
io.on('connection', (socket) => {
socket.on('chat message', (msg) => {
// io.emit('chat message', msg);
// socket.broadcast.emit('hi');
socket.emit('chat message', msg);
});
});
httpServer.listen(3000, () => {
console.log('http://localhost:3000')
});
具体实现可以参照socketio官网:Socket.IO