一些有用的工具
node-dev
- 当文件更新时自动重启的node
- 避免每次改完代码都要重新运行的麻烦(不宜在生产环境使用)
ts-node
- 让node支持直接运行TypeScript代码(不宜在生产环境使用)
ts-node-dev
- 上面两个工具的升级版,结合了两种工具的功能
- 可以用TypeScript开发Node.js程序,且会自动重启(不适合生产环境使用)
安装
yarn global add ts-node-dev
或者
npm i -g ts-node-dev
WebStorm 自动格式化
- Reformation Code 设置为 Ctrl + L 或者其他键位可以快速格式化TS/JS代码
WebStorm 自动写代码
- Complete Current Statement 设为 Ctrl+Enter
- Show Context Actions 设为 Alt + Enter 把冲突的键位改成其他快捷键
VSCode 配置
- 开启自动保存,开启保存时自动格式化
- 也可以Shif+Alt+F 手动格式化
- Quick Fix 默认快捷键 Ctrl + 句号
WebStorm Git 配置
- 把WebStorm 的git 路径设置为cmder里的
- 示例:D:\yu\Software\cmder\vendor\git-for-windows\bin\git.exe
- 好处是统一管理统一配置
VSCode Git 配置
在settings.json里添加
"git.enabled": true,
"git.path": "E:\\software\\cmder\\vendor\\git-for-windows\\cmd\\git.exe",
"terminal.integrated.profiles.windows": {
"bash": {
"path": "E:\\software\\cmder\\vendor\\git-for-windows\\bin\\bash.exe",
"args": []
}
},
curl 构造请求
- GET请求:curl -v url
- POST请求:curl -v -d “name=yume” url
- 设置请求头:-H ‘Content-Type:application/json’
- 设置动词:-X PUT
- JSON请求:curl -d ‘{“name”:“bob”}’ -H ‘Content-Type:appliction/json’ url
创建项目
步骤
- yarn init -y
- 新建 index.js,使用命令行或者WebStorm启动
- yarn add --dev @types/node 安装node声明文件
- 引入 http 模块,用http 创建server
- 监听server 的request事件,server.listen(8888) 开始监听8888端口
- 使用curl -v http://localhost:8888 发请求
启动:ts-node-dev index.ts
import * as http from 'http';
import {IncomingMessage, ServerResponse} from 'http';
const server = http.createServer();
server.on('request', (request: IncomingMessage, response: ServerResponse) => {
console.log('有人请求了');
response.end('hi');
});
server.listen(8888);
server是什么?
http.Server 类的实例
- 根据文档知道 http.createServer的返回值类型
- 所有server是http.Server的实例,server拥有几个事件和方法
- 其中request事件和listen()方法上面的实例就有用到
继承net.Server类
- 根据文档知道http.Server继承了net.Server
- server因此拥有了error事件和address()方法 等事件和方法
用Node.js 获取请求内容
get请求
- request.method 获取请求动词
- request.url 获取请求路径(含查询参数)
- request.header 获取请求头
- get请求一般贸易消息体/请求体
post请求
- curl -v -d “name=yume” http://localhost:8888
- request.on(‘data’,fn) 获取消息体
- request(‘end’,fn) 拼接消息体
request、response 是什么
找到对应的类
- request是http.IncomingMessage的实例
- response his http.ServerResponse的实例
Request
- 拥有headers、method、url等属性
- 从stream.Readable类继承了data/end/error事件
- 为什么不能直接拿到请求的消息体呢?跟TCP有关
Response
- 拥有getHeader/setHeader/end/write等方法
- 拥有statusCode属性,可读可写
- 继承了 Stream
import * as http from 'http';
import {IncomingMessage, ServerResponse} from 'http';
const server = http.createServer();
server.on('request', (request: IncomingMessage, response: ServerResponse) => {
console.log(request.method);
console.log(request.url);
console.log(request.headers);
const array: Buffer[] = [];
request.on('data', (chunk: Buffer) => {
array.push(chunk);
});
request.on('end', () => {
const body = Buffer.concat(array).toString();
console.log('body');
console.log(body);
response.statusCode = 404;
response.setHeader('X-frank', `I'm Frank`);
response.setHeader('Content-Type', 'image/png');
response.write('1\n');
response.end();
});
});
server.listen(8888);
根据 url 返回不同的文件
import * as http from 'http';
import {IncomingMessage, ServerResponse} from 'http';
import * as fs from 'fs';
import * as p from 'path';
import * as url from 'url';
const server = http.createServer();
const publicDir = p.resolve(__dirname, 'public'); //public所在的绝对路径 __dirname表示当前目录
server.on('request', (request: IncomingMessage, response: ServerResponse) => {
const {method, url: path, headers} = request;
const {pathname,search} = url.parse(path!);
// 或者解构的时候默认空字符串
// const {pathname,search} = url.parse(path || '');
switch (pathname) {
case '/index.html':
response.setHeader('Content-Type', 'text/html;charset=utf-8');
fs.readFile(p.resolve(publicDir, 'index.html'), (error, data) => {
if (error) throw error;
response.end(data.toString());
});
break;
case '/style.css':
response.setHeader('Content-Type', 'text/css;charset=utf-8');
fs.readFile(p.resolve(publicDir, 'style.css'), (error, data) => {
if (error) throw error;
response.end(data.toString());
});
break;
case '/main.js':
response.setHeader('Content-Type', 'text/javascript;charset=utf-8');
fs.readFile(p.resolve(publicDir, 'main.js'), (error, data) => {
if (error) throw error;
response.end(data.toString());
});
break;
default:
response.statusCode = 404;
response.end();
}
});
server.listen(8888);
添加缓存选项
//加上 'Cache-Control', 'public, max-age=31536000'
import * as http from 'http';
import {IncomingMessage, ServerResponse} from 'http';
import * as fs from 'fs';
import * as p from 'path';
import * as url from 'url';
const server = http.createServer();
const publicDir = p.resolve(__dirname, 'public'); //public所在的绝对路径 __dirname表示当前目录
let cacheAge = 3600 * 24 * 365;
server.on('request', (request: IncomingMessage, response: ServerResponse) => {
const {method, url: path, headers} = request;
const {pathname, search} = url.parse(path || '');
if (method !== 'GET') {
response.statusCode = 200;
response.end('这是一个假响应');
return;
}
// response.setHeader('Content-Type', 'text/html;charset=utf-8');
// /index.html => index.html
let filename = pathname!.substr(1);
if (filename === '') {
filename = 'index.html';
}
fs.readFile(p.resolve(publicDir, filename), (error, data) => {
if (error) {
console.log(error);
if (error.errno === -4058) {
response.statusCode = 404;
fs.readFile(p.resolve(publicDir, '404.html'), (error, data) => {
response.end(data);
});
} else if (error.errno === -4068) {
response.statusCode = 403;
response.end('无权限查看此目录');
} else {
response.statusCode = 500;
response.end('服务器繁忙,请稍等');
}
} else {
//返回文件内容
response.setHeader('Cache-Control', `public, max-age=${cacheAge}`);
response.end(data);
}
});
});
server.listen(8888);