node.js 静态服务器开发准备

Rinsann 2021年10月30日 655次浏览

一些有用的工具

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类

用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);