nodejs01——安装及使用、服务端及客户端、commonjs规范、fs模块的使用(文件操作及目录操作)、stream、buffer、WebServer、端口、动态资源及静态资源、头信息、请求方式

nodejs的安装及使用
服务端及客户端
commonjs规范
fs模块的使用(文件操作及目录操作)
stream
buffer

//

Node.js介绍

Node.js 诞生于2009年,Node.js采用C++语言编写而成,是 一个Javascript的运行环境。Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境 ,让JavaScript的运行脱离浏览器端,可以使用JavaScript语言 书写服务器端代码。

安装Node.js

Node.js官网下载稳定版本,node偶数版本为稳定版本,奇数版本为非稳定版本。

  • mac 直接安装 或者 brew来安装

  • 安装完Node.js会自动安装NPM(Node Package Manager):包管理工具;

  • 打开终端cmd,通过指令 node -v 来查看是否安装完成(出现版本号即是安装完成)

  • 查看node版本号;npm -v 来查看npm版本

初步感受nodejs:用nodejs创建一个服务器

index.js
//引入http模块
let http = require("http");
//创建一个服务器
let serve = http.createServer((req,res)=>{
    console.log("hello");
    res.write("hello");
    res.end("hello world");
})
//设置端口号
serve.listen(3000);

index.js可通过node去启动服务,node + index.js路径
通过浏览器访问localhost:3000(服务端)
另一台同局域网下的电脑访问则是客户端

npm i nodemon -g #安装nodemon
nodemon自动刷新node服务,无需Ctrl+C两次刷新

- Google Chrome 默认非安全端口列表,尽量避免以下端口。

    1,    // tcpmux
    7,    // echo
    9,    // discard
    11,   // systat
    13,   // daytime
    15,   // netstat
    17,   // qotd
    19,   // chargen
    20,   // ftp data
    21,   // ftp access
    22,   // ssh
    23,   // telnet
    25,   // smtp
    37,   // time
    42,   // name
    43,   // nicname
    53,   // domain
    77,   // priv-rjs
    79,   // finger
    87,   // ttylink
    95,   // supdup
    101,  // hostriame
    102,  // iso-tsap
    103,  // gppitnp
    104,  // acr-nema
    109,  // pop2
    110,  // pop3
    111,  // sunrpc
    113,  // auth
    115,  // sftp
    117,  // uucp-path
    119,  // nntp
    123,  // NTP
    135,  // loc-srv /epmap
    139,  // netbios
    143,  // imap2
    179,  // BGP
    389,  // ldap
    465,  // smtp+ssl
    512,  // print / exec
    513,  // login
    514,  // shell
    515,  // printer
    526,  // tempo
    530,  // courier
    531,  // chat
    532,  // netnews
    540,  // uucp
    556,  // remotefs
    563,  // nntp+ssl
    587,  // stmp?
    601,  // ??
    636,  // ldap+ssl
    993,  // ldap+ssl
    995,  // pop3+ssl
    2049, // nfs
    3659, // apple-sasl / PasswordServer
    4045, // lockd
    6000, // X11
    6665, // Alternate IRC [Apple addition]
    6666, // Alternate IRC [Apple addition]
    6667, // Standard IRC [Apple addition]
    6668, // Alternate IRC [Apple addition]

    6669, // Alternate IRC [Apple addition]


模块化

一、为什么会有模块化

  • 在JavaScript发展初期就是为了实现简单的页面交互逻辑,寥寥数语即,如今随着前端代码日益膨胀

    这时候JavaScript作为嵌入式的脚本语言的定位动摇了,JavaScript却没有为组织代码提供任何明显帮助,JavaScript极其简单的代码组织规范不足以驾驭如此庞大规模的代码;

二、Node.js中的模块化 commonjs规范
(Node.js模块化commonjs规范:不存在变量污染,文件独立)

  • CommonJS就是为JS的表现来制定规范,因为js没有模块的功能所以CommonJS应运而生,它希望js可以在任何地方运行,不只是浏览器中。

    1、创建自定义模块

    • 引入一个文件 形式模块

      home.js执行文件

      console.log("我是 home.js");
      //通过require来引入
      require("./aModule"); //注意一定要有"./",文件后缀可加可不加。
      console.log(a);//undefined,文件间相互独立,为防止变量污染,提高可读性
      

      amodule.js文件

      console.log("我是amodule模块111");
      let a = 20;
      
    • 引入文件夹形式模块

      • home.js执行文件
      require("./aModuledir"); //必须加"./"
      

      ​ aModuleDir里的index.js文件,会自动查找文件夹下的index.js文件执行

      console.log("我是aModule模块文件夹");
      
      • 当然也可以配置默认启动文件,在文件夹内新建package.json来指定执行文件
      {
        "name":"aModule",
        "version":"1.0.0",
        "main":"test.js"
      }
      
  • 自定义模块的按需导出

    通过module.exports 导出; ___dirname , __filename

    module.exports = {
        a:"我是a的值",
        b(){
            console.log("我是导出的b函数");
        }
    }
    

    引入导出文件

    let mymodule = require("bModule");
    console.log(mymodule.a);
    mymodule.b();
    

    或者 通过 exports来导出

    exports.fn = function(){
        console.log("我是fn函数");  
    }
    

    导入文件

    let myfn = require("bModule").fn;
    myfn();
    // 或者 通过解构赋值 
    let { fn } = require("bModule");
    fn();
    
  • 模块加载的优先级 ,先文件再目录;

///

console.log("我是Ma.js文件");
require("./Mb");
let a = 10;
class Person {
    constructor() {
        this.name = "张三";
    }
    hobby() {
        console.log("喜欢篮球");
    }
}

// 按需导出:模块导出
// module.exports = {
//     a,
//     Person
// }

// 按需导出:单个导出
exports.a = a;
exports.Person = Person;
// exports 是 module.exports 的引用,也就是module.exports = exports;

// AMD sea.js  CMD require.js
console.log("我是index.js");
let Ma = require("./Ma");
// console.log(a);
console.log(Ma.a);

// let cai = new Ma.Person();
// cai.hobby();

// require("./home");//引入执行home文件夹内的文件

// node_modules里的模块: 可不加./   如下require("mytest")
// let { a, b } = require("mytest");
// console.log(a);
// b();

// require("mytest")
// const http = require("http");

// npm:包管理器
// dependencies:运行依赖jquery、vue、react  ;
// devDependencies:开发依赖 sass less;

// 创建node服务器
// const http = require("http");//http是内置模块,可以理解成安装node后就内置有http了
// const serve = http.createServer((req, res) => {
//     res.write("hello world111");
//     res.end();
// });
// serve.listen(3000);

//

2、内置模块;

nodejs内置模块有:Buffer,C/C++Addons,Child Processes,Cluster,Console,Crypto,Debugger,DNS,Domain,Errors,Events,File System,Globals,HTTP,HTTPS,Modules,Net,OS,Path,Process,P unycode,Query Strings,Readline,REPL,Stream,String Decoder,Timers,TLS/SSL,TTY,UDP/Datagram,URL, Utilities,V8,VM,ZLIB;

内置模块不需要安装,外置模块需要安装;

npm包管理器(模块管理器)

NPM(Node Package Manager) 官网的地址是 npm官网

  • npm常用指令;
    • npm init:引导创建一个package.json文件
    • npm help(npm -h) :查看npm帮助信息
    • npm version (npm -v) : 查看npm版本;
    • npm search:查找
    • npm install (npm i):安装 默认在当前目录,如果没有node_modules 会创建文件夹;
      • npm install module_name -S 或者–save 即 npm install module_name --save 写入dependencies运行依赖
      • npm install module_name -D 或者 —save-dev 即 npm install module_name --save-dev 写入devDependencies开发依赖
      • npm install module_name -g 全局安装(命令行使用)
      • 指定版本安装模块 npm i module_name @1.0 通过 "@"符号指定;
    • npm update(npm -up):更新
    • npm remove 或者 npm uninstall:删除
    • npm root 查看当前包安装的路径 或者通过 npm root -g 来查看全局安装路径;

fs模块

  • fs是文件操作模块,所有文件操作都是有同步和异步之分,特点是同步会加上 “Sync” 如:异步读取文件 “readFile”,同步读取文件 “readFileSync”;

    文件操作

    • 文件读取:

      • 异步读取
      let fs = require("fs");
      fs.readFile("1.txt",(err,data)=>{
          if(err){
              return console.log(err);
          }
          console.log(data.toString());
      })
      

      第一个参数是读取文件的路径;
      第二个参数是读取的编码格式;(可省略不写)utf8
      第三个参数是回调函数;

      • 同步读取文件
      let fs = require("fs");
      let res = fs.readFileSync("1.txt");
      console.log(res.toString());
      

同步需要拿到返还值;
异步需要回调函数拿到结果;

  • 文件写入:

    let fs = require("fs");
    //flag配置  "a":追加写入,"w":写入,"r":读取
    fs.writeFile("2.txt","我是要写入的内容",{flag:"w"},err=>{
        if(err){
            return console.log(err);
        }
        console.log("写入成功");   
    })
    
  • 文件删除

    fs.unlink("2.txt",err=>{
        if(err){
            return console.log(err);
        }
        console.log("删除成功");
    })
    
  • 复制文件

    • 先读取文件再写入文件
    function mycopy(src,dest){//src:读取路径;dest:写入路径
       fs.writeFileSync(dest,fs.readFileSync(src));
    }
    mycopy("1.txt","4.txt");
    
fs.copyFile("index.html","myindex.html",err=>{
     if(err){
         return console.log(err);
     }
     console.log("复制成功!");
 })
  • 修改文件名,目录也可以通过rename来操作
  fs.rename("1.txt","5.txt",function (err) {
        if(err){
            console.log(err);
        }else{
            console.log("修改成功");
        }
    });
  • 判断文件是否存在
  fs.exists("4.txt",function (exists) {
        console.log(exists);
  })
const fs = require("fs"); //文件操作
// 增删改查;
// 1.文件操作  2.目录操作;

// 文件操作
// fs.writeFile("1.txt","我是写入的文字",function(err){
//     if(err){
//         return console.log(err);
//     }
//     console.log("写入成功");
// })

// 第三个参数(配置项)a:追加写入;w 写入;r:读取;
// fs.writeFile("1.txt","我是追加的文字",{flag:"a"},function(err){
//     if(err){
//         return console.log(err);
//     }
//     console.log("写入成功");
// })

// 文件读取
// fs.readFile("1.txt","utf8",(err,data)=>{
//     if(err){
//         return console.log(err);
//     }
//     console.log(data);
// })
// fs.readFile("1.txt",(err,data)=>{
//         if(err){
//             return console.log(err);
//         }
//         console.log(data.toString());
//     })

// 所有文件操作 没有加Sync都是异步 否则是同步;
// let data = fs.readFileSync("1.txt");
// console.log(data.toString());

// 修改;(修改名称);
// fs.rename("1.txt","2.txt",err=>{
//     if(err){
//         return console.log(err);
//     }
//     console.log("修改成功");
// });

// 删除;
// fs.unlink("2.txt",(err)=>{
//     if(err){
//         return console.log(err);
//     }
//     console.log("删除成功");
// })

// 复制; 先读取 在写入 的过程;
// fs.copyFile("index.html","myindex.html",err=>{
//     if(err){
//         return console.log(err);
//     }
//     console.log("复制成功!");
// })

// 复制
// function mycopy(src,dest){
//    fs.writeFileSync(dest,fs.readFileSync(src));
// }
// mycopy("index.html","test.html");

// 目录操作
// 创建目录
// fs.mkdir("11",err=>{
//     if(err){
//         return console.log(err);
//     }
//     console.log("创建成功");
// })

// 修改目录名称
// fs.rename("11", "22", err => {
//     if (err) {
//         return console.log(err);
//     }
//     console.log("修改成功");
// })

// 读取目录;
// fs.readdir("22",(err,data)=>{
//     if(err){
//         return console.log(err);
//     }
//     console.log(data);
// })

// 删除目录(空文件夹/目录)
// fs.rmdir("11",err=>{
//     if(err){
//         return console.log(err);
//     }
//     console.log("删除成功");
// })

// 判断文件或者目录是否存在
// fs.exists("index.html",exists=>{
//     console.log(exists);
// })

// 获取文件或者目录的详细信息;
// fs.stat("index.html",(err,stat)=>{
//     if(err){
//         return console.log(err);
//     }
//     // console.log(stat);
//     // 判断文件是否是文件
//     // let res = stat.isFile();
//     // 是否是一个文件夹;
//     let res = stat.isDirectory();
//     console.log(res);
// })

// 封装删除非空文件夹;
// 先把目录里的文件删除-->删除空目录;
// 22
function removeDir(path) {
    let data = fs.readdirSync(path);
    // ["33","1.txt","2.html"];
    for (let i = 0; i < data.length; i++) {
        // 是文件或者是目录; --->?文件 直接删除?目录继续查找;  
        let url = path + "/" + data[i];
        let stat = fs.statSync(url);
        if (stat.isDirectory()) {
            //目录 继续查找;
            removeDir(url);//递归删除
        } else {
            // 文件 删除
            fs.unlinkSync(url);
        }
    }
    //  删除空目录
    fs.rmdirSync(path);
}
removeDir("22");//执行删除非空文件夹

buffer缓冲区

  • buffer的创建
    • 直接创建
    • 数组创建
    • 字符串创建
    • 乱码的处理
    • buffer转换tostring
// buffer创建
// new Buffer()
// let buffer = Buffer.alloc(10);
// console.log(buffer);
// let buffer = Buffer.from("大家好");
// console.log(buffer);
// let buffer = Buffer.from([0xe5,0xa4,0xa7,0xe5,0xae,0xb6,0xe5,0xa5,0xbd]);
// console.log(buffer.toString());

let buffer1 = Buffer.from([0xe5,0xa4,0xa7,0xe5]);
let buffer2 = Buffer.from([0xae,0xb6,0xe5,0xa5,0xbd]);
// // console.log(buffer1.toString());
// let newbuffer = Buffer.concat([buffer1,buffer2]);
// console.log(newbuffer.toString());

let { StringDecoder } = require("string_decoder");
let decoder =  new StringDecoder();
let res1 = decoder.write(buffer1);
let res2 = decoder.write(buffer2);
console.log(res1+res2);
// console.log(res2);

stream流

  • stream流:流与数据处理方面密不可分
    • 流的原理
    • 流数据的获取
      • pipe
      • data
      • end
    • copy的流方法实现
    • 加载视图的流方法实现
// stream 流;
const fs = require("fs");
// let res = fs.readFileSync("1.txt");
// console.log(res.toString());
let rs = fs.createReadStream("1.txt");//分量读,一点一点读,防止爆仓内存不足的情况;

let ws = fs.createWriteStream("2.txt");
rs.pipe(ws);//把1里面读取的数据写入2内,通过pipe管道写入

 let num = 0;
 let str = "";
 rs.on("data",chunk=>{
     num++;
     str += chunk;
     // console.log(chunk);
     console.log(num);
 })
 // 流完成了;
 rs.on("end",()=>{
   console.log(str);
 })
 
// 流会把数据分成64kb的小文件传输;

// 创建一个65kb的文件;
// let buffer = Buffer.alloc(64*1024);
// fs.writeFile("65kb",buffer,err=>{
//     if(err){
//         return console.log(err);
//     }
//     console.log("写入成功");
// })

从浏览器输入 URL 到页面展示过程的过程中发生了什么?

1、在浏览器地址栏输入 URL 并回车/跳转 发送的时候,浏览器会调用内部资源加载器(类似浏览器内置的下载工具或迅雷等)加载相应资源。

依据协议的不同加载方式也不一样:

​ ——1、file协议,根据url路径加载本地资源。

​ ——2、http等协议,根据url加载(下载)网络中的资源。

2、通过IP(如果是域名,则会先通过DNS转成对应IP)定位到指定的目标资源所在的主机,并等待主机处理和响应。

3、主机对每次的请求进行分析,并通过请求携带的端口转发给对应的处理程序(QQ的消息交给QQ这个软件处理,微信的消息交给微信这个软件处理),通常针对 http 这种请求,相关数据交由主机指定的软件进行处理(称为 WebServer APP,如:Nginx、Apache、IIS、Tomcat……)

4、WebServer 分析请求信息,如请求的方式,请求的路径,请求携带的其他各种规定好的或自定的数据。根据这些数据,以及自己定义的业务规则,处理数据,然后进行返回。返回的数据可以是JSON格式的字符串,也可以是HTML格式的字符串,或者各种图片、音频、视频等数据。

5、浏览器接收资源加载器请求(主机返回)的数据,然后根据得到的内容类型进行解析处理。

6、如果浏览器解析过程中,比如解析的是html内容,碰到类似link,script,img等标签,又或者是后续用户的一些行为,如点击a链接,提交一个表单等,再次触发资源加载请求,重复上述步骤……

通常,我们把发送请求(需求)的一方称为:客户端。接收请求(提供服务)的一方成为:服务端

WebServer

WebServer 本质上就是一个软件,一个用来处理网络数据交互的程序,它可以用任何具备网络编程的语言来实现,如:c、c++、java,python,php 等,我们前面介绍的 Node.js 也可以。

基于 Node.js 构建 WebServer

Node.js 中已经内置提供了一个模块: http ,这个模块就提供了实现 http 所需要的 API:

  • 提供了服务端接口,用来响应客户端发送的 http 请求。
  • 提供了客户端接口,可以像浏览器一样发送请求到其它服务端。

https://nodejs.org/dist/latest-v12.x/docs/api/http.html

创建 WebServer

我们要创建一个 WebServer,需要使用 http 模块下 http.Server 类来创建一个 Server 对象,我们可以通过一个静态工厂方法 http.createServer 来得到该类的实例对象:

// [file: app.js]

// 首先通过 require 引入 http 模块
const http = require('http');

// 创建一个 Server 对象
const server = http.createServer();

端口的意义

一台主机的网卡数量是有限的,不可能为主机上的每一个程序去安装一个网卡。为了解决不同的应用程序共享网卡而不至于数据混乱的问题,系统会准备一批端口(类似银行窗口),由需要使用端口进行数据通信的程序去申请(监听),申请成功以后,就可以进行网络数据交互了。

通常,监听端口数据需要程序主动指定。发送请求由系统随机分配,如:

主机:111.111.111.111 监听 8888 端口

客户端发送请求:222:222:222:222:4567 => (发送数据) => 111.111.111.111:8888

注:端口取值范围为:1-65535,即 216 。通常约定1-1023之间的端口为系统常见程序预留端口,1024-5000为通信临时随机端口,5000以后为用户自定端口。

//端口:把数据与具体应用(比如当前server)进行绑定的一个机制
server.listen(8888,"0.0.0.0");//0.0.0.0是通配,默认的;//8888是指定端口进行访问

// 方式2
server.listen(8888,()=>{
	console.log("服务启动成功,访问地址:http://localhost:8888");
});

端口监听

// [file: app.js]

// 首先通过 require 引入 http 模块
const http = require('http');

// 创建一个 Server 对象
const server = http.createServer();

// 监听一个指定的端口,第二参数如果是指定要监听的网卡所在网络的IP(一台机器可能存在多个网卡,一个网卡也可能会在多个不同的网络中,127.0.0.1 默认指本地回环网络,即自己给自己通信的特殊IP,同时有个默认的域localhost,0.0.0.0 表示所有网卡所有IP,可省略),
server.listen(8888, '127.0.0.1', () => {
  console.log('服务已经启动了,http://127.0.0.1:8888');
});

//等同于以下

server.on('request', () => {
  console.log('服务已经启动了,http://127.0.0.1:8888');
});

使用 Node 解析器执行该程序,程序就会进入监听状态(不会退出)

node app.js

处理用户请求

server 会提供一些的事件,我们通过 Node.js 内置的 on 方法来监听这些事件,完成对应的业务处理。

当服务启动成功以后,客户端就可以通过发送对应的 http 请求(http://127.0.0.1:8888)来完成与上述服务器的通信了。

因为浏览器在发送请求的时候,默认端口为 80,所以,如果服务端监听的是 80 端口,那么浏览器在请求过程中可以不需要显式填写端口了,http://127.0.0.1:80 => http://127.0.0.1

request 事件

当服务启动成功以后,我们可以监听 server 对象的 request 事件来处理客户端请求。

// [file: app.js]

//...

server.on('request', () => {
  console.log('有客户端发送了一个请求');
});

//...

我们还可以在 http.createServer 的时候传入一个 callback 参数,这个 callback 就是 request 事件的回调函数。

// [file: app.js]

// 首先通过 require 引入 http 模块
const http = require('http');

// 创建一个 Server 对象
const server = http.createServer(() => {
  console.log('有客户端发送了一个请求');
});

server.listen(8888, () => {
  console.log('服务已经启动了,http://127.0.0.1:8888');
});

request 事件回调函数中会自动传入两个参数,供我们进行后续的业务逻辑调用:

  • http.IncomingMessage(req):一个 Node.js 封装好的对象,与当前请求的客户端相关信息(客户端请求提交的数据,IP等)和方法都是通过该对象来完成。
  • http.ServerResponse(res):也是一个 Node.js 封装好的对象,提供了服务端信息和方法,比如向客户端发送数据的方法就由该对象提供。

http.IncomingMessage 对象(req)

一个 Node.js 封装好的对象,与当前请求的客户端相关信息(客户端请求提交的数据,IP等)和方法都是通过该对象来完成。

一些常用属性和方法:

  • url: 当前客户端请求的 url,http://域名:端口 后面的部分,不包含 http://域名:端口。
  • headers: 当前客户端请求携带的头信息数据。
  • method: 当前客户端所使用的请求方法。
  • httpVersion:当前客户端请求所使用的 http 协议的版本。
  • on(): 监听一些事件。

http.ServerResponse 对象(res)

也是一个 Node.js 封装好的对象,提供了服务端信息和方法,比如向客户端发送数据的方法就由该对象提供。

一些常用的属性和方法:(write、end、setHeader、statusCode、statusMessage、writeHead)

  • write(chunk[, encoding][, callback]):服务端发送数据给客户端的方法,但是需要调用end方法来结束当前请求。
  • end([data[, encoding]][, callback]):与write类似。
  • setHeader(name, value): 设置发送给客户端的额外信息(头信息)。
  • statusCode:响应状态码。
  • statusMessage:响应状态码对应的文本。
  • writeHead(statusCode[, statusMessage][, headers]):与 end 类似,注意:调用 writeHead 以后不能在进行头信息设置了。
// [file: app.js]

// 首先通过 require 引入 http 模块
const http = require('http');

// 创建一个 Server 对象
const server = http.createServer((req, res) => {
  // 代表了客户端的 req 对象
  console.log('req', req);
  // 代表了服务端的 res 对象
  console.log('res', res);
});

server.listen(8888, () => {
  console.log('服务已经启动了,http://127.0.0.1:8888');
});

url 的作用

我们通常会通过一个 URL 来访问不同的内容。这里的 URL 也称为: 统一资源定位符(Uniform Resource Locator)

参考:

在这里插入图片描述

每一个互联网中的资源(资源可以是一段HTML字符串、HTML文件、CSS文件、JS文件、图片、视频、音频……)都会通过一个 URL 来与之对应,但是这种对应关系需要程序(WebServer)来实现。比如:http://kaikeba.com/js/hello 这个 URL 在找到 kaikeba.com 这个主机(服务器)以后,/js/hello 这个虚拟的 URL 路径会返回对应的内容是什么,它可以直接返回一个字符串,也可以返回一个服务器在某个地方存储的文件,也也也可以是这个服务器去另外一个主机上读取的内容。

req.url

我们可以通过分析每次请求的 url 来获取当前客户端要请求的资源。

// [file: app.js]

// 首先通过 require 引入 http 模块
const http = require('http');

// 创建一个 Server 对象
const server = http.createServer((req, res) => {
  // 当前请求的 url
  console.log('req.url', req.url);
});

server.listen(8888, () => {
  console.log('服务已经启动了,http://127.0.0.1:8888');
});

res.write AND res.end

根据不同的请求 URL 以及当前具体业务逻辑,通过 res 对象的 writeend 方法向客户端返回这次请求的结果。

// [file: app.js]

// 首先通过 require 引入 http 模块
const http = require('http');
const fs = require('fs');

// 创建一个 Server 对象
const server = http.createServer((req, res) => {
  const url = req.url;
  let resContent = '';
  
  // 针对不同url进行不同的处理
  if (url == '/') {
    // 返回一个字符串
    resContent = 'hello';
  } else if (url == '/now') {
    resContent = (new Date).toString();
  } else if (url == '/kkb.html') {
    resContent = fs.readFileSync('./kkb.html');
    } else {
    resContent = '啥也没有';
  }
  
  res.end(resContent);
});

server.listen(8888, () => {
  console.log('服务已经启动了,http://127.0.0.1:8888');
});

静态资源 Vs 动态资源

许多时候,我们会把资源简单的划分成:

  • 静态资源
  • 动态资源

静态资源

相对不变的内容(除非你修改了它的内容),类似程序中的 变量与常量。

比如前面 / 、/kkb.html 以及 最后那个 啥也没有,就是静态内容,除非你去修改内容本身,否则访问对应的 URL ,返回的内容永远不变。

动态资源

与静态资源不同,同一个 URL 返回的内容并不固定,比如访问 /now 这个 URL,即使不做任何修改,你就有可能得到不一样的结果,这就是动态资源。

静态资源代理(处理)服务

通常,我们的 WebServer 会提供各种静态资源(html代码、css代码、js代码、图片……),而这些资源我们又通常会通过文件的方式存储在某个地方。为了批量处理这种资源与 URL 的对应关系,我们会根据某种规则(规则自己定义,或者说由实现WebServer的各种软件和框架)来自动映射。

我们把静态资源文件存放在服务器的某个位置,如:

  • D:/kkb/public/

同时我们去解析请求的 URL,只要 URL 上的路径符合某种规则(自定),如:

  • /public/1.html

那么我们可以根据这种规则,利用 fs 去读取对应的文件,只需要按照 URL 去生成对应的真实文件路径即可:

// [file: app.js]

// 首先通过 require 引入 http 模块
const http = require('http');
const fs = require('fs');

// 创建一个 Server 对象
const server = http.createServer((req, res) => {
  const url = req.url;
  let resContent = '';
  
  // 针对不同url进行不同的处理
  if (url.startsWith('/public')) {
    // 真实文件存储的位置自己写的自己定,用别人写的就根据别人的规则定,原理一样
    // resContent = fs.readFileSync('D:/kkb' + url);
    resContent = fs.readFileSync('.' + url);
  } else {
    // 这里处理动态资源,以及其它一些情况
    if (url == '/now') {
      resContent = (new Date).toString();
    } else {
      resContent = '啥也没有';
    }
  }
  
  res.end(resContent);
});

server.listen(8888, () => {
  console.log('服务已经启动了,http://127.0.0.1:8888');
});

头信息

头信息是每次请求和响应的时候所携带的一些非主体内容相关的信息,用于请求和接收方作为某种处理依据(但其本身并非主要内容),比如请求的时候所使用的代理(如浏览器,请求并不一定是浏览器发起,比如迅雷等下载软件也可以发送http请求)。作用类似写信(邮件)所填写的邮编、邮箱地址等非信件本身的信息。

由的头信息只能在请求中设置,有的只能在响应中设置,而有的双方都可以设置。

参考:https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers

Content-Type

设置发送的内容 MIME 类型

参考:https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Content-Type

MIME

参考:

https://baike.baidu.com/item/MIME/2900607

https://en.wikipedia.org/wiki/MIME

http://www.iana.org/assignments/media-types/media-types.xhtml

动态资源处理

许多时候,动态资源会相对复杂一些,有的时候需要根据业务产生一些数据,同时又会把这个数据进行一些包装(嵌入到HTML代码)中,如果每次都字符串拼接去做会比较麻烦:

  • 拼接数据和html字符串毕竟麻烦,且容易出错。
  • 逻辑处理很繁琐,同样也容易出错。
  • 不容易维护,前端页面处理(html、css等)和后端(Node.js)代码混合。
  • ……

模板引擎

把数据与某个模板文件(通常是类似HTML,但是又包含了一些特殊定义的语法的字符串/文件),进行结合,利用引擎(写好的方法)去对模板文件中的特殊语法(模板引擎定义语法 - 语法取决于具体模板引擎)进行解析,得到最终的 HTML 字符串。

Nunjucks

参考:

https://mozilla.github.io/nunjucks/

https://nunjucks.bootcss.com/

queryString

在 URL 中,除了路径部分,还有一个 query 部分(url 的 ? 后面的内容),称为:查询字符串(queryString),通常情况下,我们可以在请求的 URL 中通过路径 ? 后面加入一种特殊组织格式的数据携带一些数据,用于服务端进行一些额外的逻辑处理。

它的结构为使用 & 或者 ; 分割的键值对字符串,键值对的 键 与 值 使用 = 进行分隔,如:

http://kaikeba.com/items?order=asc&typeId=1

参考:

https://en.wikipedia.org/wiki/Query_string

Node.js 中的 queryString 模块

我们可以自己封装处理 queryString 的方法,也可以直接使用 Node.js 内置的 queryString 模块来处理。

参考:https://nodejs.org/dist/latest-v12.x/docs/api/querystring.html

请求方式

为了规范统一和语义化资源处理的行为,在定义了 URL 这种资源定位规范以外,还定义了一套动作,也称为请求方式(请求方法)

参考:https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Methods

// 针对 POST 方式提交的数据进行单独处理
} else if (url == '/add' && req.method.toUpperCase() == 'POST') {
  let data = await new Promise(resolve => {
    let reqData = '';
    req.on('data', data => {
      console.log('data', data);
      reqData += data.toString();
    })
    req.on('end', () => {
      console.log('over');
      resolve(reqData);
    })
  })
  console.log('提交过来的数据是:', data);
  resContent = '提交成功';
}

Content-Type

同时,我们也可以通过提交过来的 Content-Type 来针对性的处理:

  • application/x-www-form-urlencoded
  • multipart/form-data
  • text/plain

注:

  • 浏览器 GET 不支持提交正文
  • queryString 属于 URL,与请求方式无关(任何方式的请求都可以携带 queryString)

工具

一些开发工具

  • nodemon: https://www.npmjs.com/package/nodemon
// 127.0.0.1 => 本机网络地址,专门自己给自己打电话所使用的号码
// console.log('欢迎欢迎', window);

// 首先通过 require 引入 http 模块
const http = require('http');

// 创建一个 Server 对象,用来处理请求
const server = http.createServer((req, res) => {
    // 当有请求的时候,会在服务端控制台打印
    console.log('有人发送了一个请求');
    // console.log('req', req);

    // localhost => 127.0.0.1

    // req => http.IncomingMessage 对象:当前发送请求的客户端对象(提供保存了与当前请求的客户端相关信息)
    // res => http.ServerResponse 对象:提供了一个服务端向客户端进行响应一些方法

    // http: 非持久性链接,http目的是返回数据资源的,不在乎他的实时性,当当前这次请求完成以后,为了保证资源不被长久占用,为更多的请求提供服务
    // res.write('Hello');
    // 告诉客户端,我们的响应以及完成了,调用 end 方法
    res.end('hello');
});

// server.on('request', () => {
//     console.log('有人发送了一个请求');
// });

// 不要让程序退出,并且要监听一个网络端口
// 端口:把数据与具体的应用程序(比如当前这个server)进行绑定的一种机制
// server.listen(8888, '0.0.0.0');
server.listen(8888, () => {
    console.log(`服务器启动成功:http://localhost:8888`);
});
const http = require('http');

const server = http.createServer((req, res) => {
    /**
     * http
     *      协议:做某件事情的一种规范和标准(约束)
     *          超文本传输协议:超文本在网络中传输的一种规范
     *          tcp/ip: 数据传输规范
     */

    console.log('有人发送了一个请求');

    // 虚拟路径,不是服务器中某个资源的真实路径
    // console.log('url', req.url);

    // 向客户端写入头信息
    let url = req.url;

    if (url === '/') {
        res.writeHead(200, 'ok', {
            'content-type': 'text/html; charset=utf-8'
        });
        res.end('<h1>欢迎来到开课吧</h1>');
    }

    if (url === '/login') {
        res.writeHead(200, 'ok', {
            'content-type': 'text/html; charset=utf-8'
        });
        res.end('<h1>登录页面</h1>');
    }
});

server.listen(8888, () => {
    console.log(`服务器启动成功:http://localhost:8888`);
});
const http = require('http');

const server = http.createServer( (req, res) => {
    let url = req.url;

    if (url === '/') {
        res.writeHead(200, 'ok', {
            'content-type': 'text/html; charset=utf-8'
        });
        res.end('<link href="css" rel="stylesheet" /><h1>欢迎来到开课吧</h1>');
    }

    if (url === '/css') {
        res.writeHead(200, 'ok', {
            'content-type': 'text/css; charset=utf-8'
        });
        res.end('body {color: red}');
    }

    if (url === '/login') {
        res.writeHead(200, 'ok', {
            'content-type': 'text/html; charset=utf-8'
        });
        res.end('<h1>登录页面</h1>');
    }
} );

server.listen(8888, () => {
    console.log(`服务器启动成功:http://localhost:8888`);
});
const http = require('http');
const fs = require('fs');

const server = http.createServer( (req, res) => {
    let url = req.url;

    // 我们把这种资源(css,js、html)保存在一个外部文件中,这样方便我们管理,编写,以及统一处理,然后我们会这种文件定义一套访问规则

    let content = '';

    if (url === '/') {
        res.writeHead(200, 'ok', {
            'content-type': 'text/html; charset=utf-8'
        });
        content = fs.readFileSync('./public/dahai.html');
        res.end(content);
    }

    if (url === '/css') {
        res.writeHead(200, 'ok', {
            'content-type': 'text/css; charset=utf-8'
        });
        content = fs.readFileSync('./public/css.css');
        res.end(content);
    }

    if (url === '/js') {
        res.writeHead(200, 'ok', {
            'content-type': 'application/javascript; charset=utf-8'
        });
        content = fs.readFileSync('./public/diange.js');
        res.end(content);
    }

} );

server.listen(8888, () => {
    console.log(`服务器启动成功:http://localhost:8888`);
});
const http = require('http');
const fs = require('fs');

const server = http.createServer( (req, res) => {
    let url = req.url;

    // 我们把这种资源(css,js、html)保存在一个外部文件中,这样方便我们管理,编写,以及统一处理,然后我们会这种文件定义一套访问规则

    /**
     * url /css.css => fs => public/css.css
     * url /dahai.html => fs => public/dahai.html
     * url /diange.js => fs => public/diange.js
     */

    let content = '';

    
    let filePath = './public' + url;

    console.log('url', url, filePath);

    if (url.includes('.ico')) {
        res.end('');
    } else {
        // 在不修改文件的基础上,访问的内容保持不变的资源 - 静态资源
        res.writeHead(200, 'ok', {
            'content-type': 'text/html; charset=utf-8'
        });
        content = fs.readFileSync(filePath);
        res.end(content);
    }
} );

server.listen(8888, () => {
    console.log(`服务器启动成功:http://localhost:8888`);
});
const http = require('http');
const fs = require('fs');

const server = http.createServer( (req, res) => {
    let url = req.url;

    // 我们把这种资源(css,js、html)保存在一个外部文件中,这样方便我们管理,编写,以及统一处理,然后我们会这种文件定义一套访问规则

    /**
     * url /css.css => fs => public/css.css
     * url /dahai.html => fs => public/dahai.html
     * url /diange.js => fs => public/diange.js
     */

    let content = '';
     
    // let filePath = './public' + url;

    // console.log('url', url, filePath);

    if (url.includes('.ico')) {
        res.end('');
    } else {
        
        // 把动态资源和静态资源的访问规则制定一下,加以区别

        if (url.startsWith('/public')) {
            let filePath = '.' + url;

            res.writeHead(200, 'ok', {
                'content-type': 'text/html; charset=utf-8'
            });
            content = fs.readFileSync(filePath);
            res.end(content);
        } else {
            // 动态资源的url一般没有太多的规则,所以一般都需要一个一个的定义
            if (url === '/getDateTime') {
                res.writeHead(200, 'ok', {
                    'content-type': 'text/html; charset=utf-8'
                });
                res.end(new Date().toString());
            }
        }       
    }
} );

server.listen(8888, () => {
    console.log(`服务器启动成功:http://localhost:8888`);
});
const http = require('http');
const fs = require('fs');
const mime = require('./mime.json');
// console.log('mime', mime);

const server = http.createServer( (req, res) => {
    let url = req.url;

    // 我们把这种资源(css,js、html)保存在一个外部文件中,这样方便我们管理,编写,以及统一处理,然后我们会这种文件定义一套访问规则

    /**
     * url /css.css => fs => public/css.css
     * url /dahai.html => fs => public/dahai.html
     * url /diange.js => fs => public/diange.js
     */

    let content = '';

    
    // let filePath = './public' + url;

    // console.log('url', url, filePath);

    if (url.includes('.ico')) {
        res.end('');
    } else {
        
        // 把动态资源和静态资源的访问规则制定一下,加以区别

        if (url.startsWith('/public')) {
            let filePath = '.' + url;

            // 因为静态资源的种类比较多,所以我们需要为不同类型的静态资源返回不同类型 content-type
            // 需要根据请求的url的特征(一般利用文件的后缀名)

            // 1、获取当前请求的url后缀
            let lastPointIndex = filePath.lastIndexOf('.');
            // 2、根据 lastPointIndex 截取这个点后面的内容
            let suffix = filePath.substring(lastPointIndex);
            // console.log('suffix', suffix);
            // 通过 suffix 获取对应的 mime
            let mimeType = mime[suffix];
            // console.log('mimeType', mimeType);


            res.writeHead(200, 'ok', {
                'content-type': mimeType + '; charset=utf-8'
            });
            content = fs.readFileSync(filePath);
            res.end(content);
        } else {
            // 动态资源的url一般没有太多的规则,所以一般都需要一个一个的定义
            if (url === '/getDateTime') {
                res.writeHead(200, 'ok', {
                    'content-type': 'text/html; charset=utf-8'
                });
                res.end(new Date().toString());
            }
        }
   
    }
} );

server.listen(8888, () => {
    console.log(`服务器启动成功:http://localhost:8888`);
});

练习要求

  • 1、使用node.js的http模块搭建一个webserver项目
    • 1-1、端口8888
  • 2、访问 http://localhost:8888/public/index.html 返回 public 目录下的 index.html 内容
    • 2-1、项目目录下创建一个 public 目录
    • 2-2、public 下创建一个 index.html 文件(文件内容不限制)
  • 3、访问 http://localhost:8888/quote 随机返回一句毒鸡汤

毒鸡汤范文

const quotes = [

‘虽然我个子矮,但我发际线高啊!’,

‘有些事情做不完,就留到明天做吧。运气好的话,明天死了就不用做了。’,

‘善良没用,你得漂亮。’,

‘好好活下去 每天都有新打击。’,

‘活着的时候把自己搞得好看一点,这样你就不会死得太难看。’,

‘世上无难事 只要肯放弃。’,

‘加油,你是最胖的!’
];

// app.js
const http = require('http');
const fs = require('fs');
const mime = require('./mime.json');

const quotes = [

    '虽然我个子矮,但我发际线高啊!',

    '有些事情做不完,就留到明天做吧。运气好的话,明天死了就不用做了。',

    '善良没用,你得漂亮。',

    '好好活下去 每天都有新打击。',

    '活着的时候把自己搞得好看一点,这样你就不会死得太难看。',

    '世上无难事 只要肯放弃。',

    '加油,你是最胖的!'
];

const server = http.createServer((req, res) => {

    let url = req.url;
    let statusCode = 200;
    let content = '';
    let mimeType = 'text/html';

    // 静态资源访问
    if (url.startsWith('/public')) {

        let filePath = '.' + url;

        try {
            let lastPointIndex = filePath.lastIndexOf('.');
            let suffix = filePath.substring(lastPointIndex);
            mimeType = mime[suffix];
            content = fs.readFileSync(filePath);
        } catch (e) {
            statusCode = 400;
            content = fs.readFileSync('./public/404.html');
        }

        res.writeHead(statusCode, {
            'content-type': `${mimeType};charset="utf-8"`
        });
        res.end(content);

    } else {
        if (url === '/quote') {
            res.writeHead(statusCode, {
                'content-type': `${mimeType};charset="utf-8"`
            });

            content = quotes.sort(() => Math.random() - .5)[0];

            res.end(content);
        }
    }

});

server.listen(8888, () => {
    console.log(`服务器启动成功:http://localhost:8888`);
});
<!-- /public/index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <h1>hello world</h1>
</body>
</html>
<!-- /public/404.html -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <h1>页面不存在!</h1>
</body>
</html>
mime.json
{ ".323":"text/h323" ,
  ".3gp":"video/3gpp" ,
  ".aab":"application/x-authoware-bin" ,
  ".aam":"application/x-authoware-map" ,
  ".aas":"application/x-authoware-seg" ,
  ".acx":"application/internet-property-stream" ,
  ".ai":"application/postscript" ,
  ".aif":"audio/x-aiff" ,
  ".aifc":"audio/x-aiff" ,
  ".aiff":"audio/x-aiff" ,
  ".als":"audio/X-Alpha5" ,
  ".amc":"application/x-mpeg" ,
  ".ani":"application/octet-stream" ,
  ".apk":"application/vnd.android.package-archive" ,
  ".asc":"text/plain" ,
  ".asd":"application/astound" ,
  ".asf":"video/x-ms-asf" ,
  ".asn":"application/astound" ,
  ".asp":"application/x-asap" ,
  ".asr":"video/x-ms-asf" ,
  ".asx":"video/x-ms-asf" ,
  ".au":"audio/basic" ,
  ".avb":"application/octet-stream" ,
  ".avi":"video/x-msvideo" ,
  ".awb":"audio/amr-wb" ,
  ".axs":"application/olescript" ,
  ".bas":"text/plain" ,
  ".bcpio":"application/x-bcpio" ,
  ".bin ":"application/octet-stream" ,
  ".bld":"application/bld" ,
  ".bld2":"application/bld2" ,
  ".bmp":"image/bmp" ,
  ".bpk":"application/octet-stream" ,
  ".bz2":"application/x-bzip2" ,
  ".c":"text/plain" ,
  ".cal":"image/x-cals" ,
  ".cat":"application/vnd.ms-pkiseccat" ,
  ".ccn":"application/x-cnc" ,
  ".cco":"application/x-cocoa" ,
  ".cdf":"application/x-cdf" ,
  ".cer":"application/x-x509-ca-cert" ,
  ".cgi":"magnus-internal/cgi" ,
  ".chat":"application/x-chat" ,
  ".class":"application/octet-stream" ,
  ".clp":"application/x-msclip" ,
  ".cmx":"image/x-cmx" ,
  ".co":"application/x-cult3d-object" ,
  ".cod":"image/cis-cod" ,
  ".conf":"text/plain" ,
  ".cpio":"application/x-cpio" ,
  ".cpp":"text/plain" ,
  ".cpt":"application/mac-compactpro" ,
  ".crd":"application/x-mscardfile" ,
  ".crl":"application/pkix-crl" ,
  ".crt":"application/x-x509-ca-cert" ,
  ".csh":"application/x-csh" ,
  ".csm":"chemical/x-csml" ,
  ".csml":"chemical/x-csml" ,
  ".css":"text/css" ,
  ".cur":"application/octet-stream" ,
  ".dcm":"x-lml/x-evm" ,
  ".dcr":"application/x-director" ,
  ".dcx":"image/x-dcx" ,
  ".der":"application/x-x509-ca-cert" ,
  ".dhtml":"text/html" ,
  ".dir":"application/x-director" ,
  ".dll":"application/x-msdownload" ,
  ".dmg":"application/octet-stream" ,
  ".dms":"application/octet-stream" ,
  ".doc":"application/msword" ,
  ".docx":"application/vnd.openxmlformats-officedocument.wordprocessingml.document" ,
  ".dot":"application/msword" ,
  ".dvi":"application/x-dvi" ,
  ".dwf":"drawing/x-dwf" ,
  ".dwg":"application/x-autocad" ,
  ".dxf":"application/x-autocad" ,
  ".dxr":"application/x-director" ,
  ".ebk":"application/x-expandedbook" ,
  ".emb":"chemical/x-embl-dl-nucleotide" ,
  ".embl":"chemical/x-embl-dl-nucleotide" ,
  ".eps":"application/postscript" ,
  ".epub":"application/epub+zip" ,
  ".eri":"image/x-eri" ,
  ".es":"audio/echospeech" ,
  ".esl":"audio/echospeech" ,
  ".etc":"application/x-earthtime" ,
  ".etx":"text/x-setext" ,
  ".evm":"x-lml/x-evm" ,
  ".evy":"application/envoy" ,
  ".exe":"application/octet-stream" ,
  ".fh4":"image/x-freehand" ,
  ".fh5":"image/x-freehand" ,
  ".fhc":"image/x-freehand" ,
  ".fif":"application/fractals" ,
  ".flr":"x-world/x-vrml" ,
  ".flv":"flv-application/octet-stream" ,
  ".fm":"application/x-maker" ,
  ".fpx":"image/x-fpx" ,
  ".fvi":"video/isivideo" ,
  ".gau":"chemical/x-gaussian-input" ,
  ".gca":"application/x-gca-compressed" ,
  ".gdb":"x-lml/x-gdb" ,
  ".gif":"image/gif" ,
  ".gps":"application/x-gps" ,
  ".gtar":"application/x-gtar" ,
  ".gz":"application/x-gzip" ,
  ".h":"text/plain" ,
  ".hdf":"application/x-hdf" ,
  ".hdm":"text/x-hdml" ,
  ".hdml":"text/x-hdml" ,
  ".hlp":"application/winhlp" ,
  ".hqx":"application/mac-binhex40" ,
  ".hta":"application/hta" ,
  ".htc":"text/x-component" ,
  ".htm":"text/html" ,
  ".html":"text/html" ,
  ".hts":"text/html" ,
  ".htt":"text/webviewhtml" ,
  ".ice":"x-conference/x-cooltalk" ,
  ".ico":"image/x-icon" ,
  ".ief":"image/ief" ,
  ".ifm":"image/gif" ,
  ".ifs":"image/ifs" ,
  ".iii":"application/x-iphone" ,
  ".imy":"audio/melody" ,
  ".ins":"application/x-internet-signup" ,
  ".ips":"application/x-ipscript" ,
  ".ipx":"application/x-ipix" ,
  ".isp":"application/x-internet-signup" ,
  ".it":"audio/x-mod" ,
  ".itz":"audio/x-mod" ,
  ".ivr":"i-world/i-vrml" ,
  ".j2k":"image/j2k" ,
  ".jad":"text/vnd.sun.j2me.app-descriptor" ,
  ".jam":"application/x-jam" ,
  ".jar":"application/java-archive" ,
  ".java":"text/plain" ,
  ".jfif":"image/pipeg" ,
  ".jnlp":"application/x-java-jnlp-file" ,
  ".jpe":"image/jpeg" ,
  ".jpeg":"image/jpeg" ,
  ".jpg":"image/jpeg" ,
  ".jpz":"image/jpeg" ,
  ".js":"application/x-javascript" ,
  ".jwc":"application/jwc" ,
  ".kjx":"application/x-kjx" ,
  ".lak":"x-lml/x-lak" ,
  ".latex":"application/x-latex" ,
  ".lcc":"application/fastman" ,
  ".lcl":"application/x-digitalloca" ,
  ".lcr":"application/x-digitalloca" ,
  ".lgh":"application/lgh" ,
  ".lha":"application/octet-stream" ,
  ".lml":"x-lml/x-lml" ,
  ".lmlpack":"x-lml/x-lmlpack" ,
  ".log":"text/plain" ,
  ".lsf":"video/x-la-asf" ,
  ".lsx":"video/x-la-asf" ,
  ".lzh":"application/octet-stream" ,
  ".m13":"application/x-msmediaview" ,
  ".m14":"application/x-msmediaview" ,
  ".m15":"audio/x-mod" ,
  ".m3u":"audio/x-mpegurl" ,
  ".m3url":"audio/x-mpegurl" ,
  ".m4a":"audio/mp4a-latm" ,
  ".m4b":"audio/mp4a-latm" ,
  ".m4p":"audio/mp4a-latm" ,
  ".m4u":"video/vnd.mpegurl" ,
  ".m4v":"video/x-m4v" ,
  ".ma1":"audio/ma1" ,
  ".ma2":"audio/ma2" ,
  ".ma3":"audio/ma3" ,
  ".ma5":"audio/ma5" ,
  ".man":"application/x-troff-man" ,
  ".map":"magnus-internal/imagemap" ,
  ".mbd":"application/mbedlet" ,
  ".mct":"application/x-mascot" ,
  ".mdb":"application/x-msaccess" ,
  ".mdz":"audio/x-mod" ,
  ".me":"application/x-troff-me" ,
  ".mel":"text/x-vmel" ,
  ".mht":"message/rfc822" ,
  ".mhtml":"message/rfc822" ,
  ".mi":"application/x-mif" ,
  ".mid":"audio/mid" ,
  ".midi":"audio/midi" ,
  ".mif":"application/x-mif" ,
  ".mil":"image/x-cals" ,
  ".mio":"audio/x-mio" ,
  ".mmf":"application/x-skt-lbs" ,
  ".mng":"video/x-mng" ,
  ".mny":"application/x-msmoney" ,
  ".moc":"application/x-mocha" ,
  ".mocha":"application/x-mocha" ,
  ".mod":"audio/x-mod" ,
  ".mof":"application/x-yumekara" ,
  ".mol":"chemical/x-mdl-molfile" ,
  ".mop":"chemical/x-mopac-input" ,
  ".mov":"video/quicktime" ,
  ".movie":"video/x-sgi-movie" ,
  ".mp2":"video/mpeg" ,
  ".mp3":"audio/mpeg" ,
  ".mp4":"video/mp4" ,
  ".mpa":"video/mpeg" ,
  ".mpc":"application/vnd.mpohun.certificate" ,
  ".mpe":"video/mpeg" ,
  ".mpeg":"video/mpeg" ,
  ".mpg":"video/mpeg" ,
  ".mpg4":"video/mp4" ,
  ".mpga":"audio/mpeg" ,
  ".mpn":"application/vnd.mophun.application" ,
  ".mpp":"application/vnd.ms-project" ,
  ".mps":"application/x-mapserver" ,
  ".mpv2":"video/mpeg" ,
  ".mrl":"text/x-mrml" ,
  ".mrm":"application/x-mrm" ,
  ".ms":"application/x-troff-ms" ,
  ".msg":"application/vnd.ms-outlook" ,
  ".mts":"application/metastream" ,
  ".mtx":"application/metastream" ,
  ".mtz":"application/metastream" ,
  ".mvb":"application/x-msmediaview" ,
  ".mzv":"application/metastream" ,
  ".nar":"application/zip" ,
  ".nbmp":"image/nbmp" ,
  ".nc":"application/x-netcdf" ,
  ".ndb":"x-lml/x-ndb" ,
  ".ndwn":"application/ndwn" ,
  ".nif":"application/x-nif" ,
  ".nmz":"application/x-scream" ,
  ".nokia-op-logo":"image/vnd.nok-oplogo-color" ,
  ".npx":"application/x-netfpx" ,
  ".nsnd":"audio/nsnd" ,
  ".nva":"application/x-neva1" ,
  ".nws":"message/rfc822" ,
  ".oda":"application/oda" ,
  ".ogg":"audio/ogg" ,
  ".oom":"application/x-AtlasMate-Plugin" ,
  ".p10":"application/pkcs10" ,
  ".p12":"application/x-pkcs12" ,
  ".p7b":"application/x-pkcs7-certificates" ,
  ".p7c":"application/x-pkcs7-mime" ,
  ".p7m":"application/x-pkcs7-mime" ,
  ".p7r":"application/x-pkcs7-certreqresp" ,
  ".p7s":"application/x-pkcs7-signature" ,
  ".pac":"audio/x-pac" ,
  ".pae":"audio/x-epac" ,
  ".pan":"application/x-pan" ,
  ".pbm":"image/x-portable-bitmap" ,
  ".pcx":"image/x-pcx" ,
  ".pda":"image/x-pda" ,
  ".pdb":"chemical/x-pdb" ,
  ".pdf":"application/pdf" ,
  ".pfr":"application/font-tdpfr" ,
  ".pfx":"application/x-pkcs12" ,
  ".pgm":"image/x-portable-graymap" ,
  ".pict":"image/x-pict" ,
  ".pko":"application/ynd.ms-pkipko" ,
  ".pm":"application/x-perl" ,
  ".pma":"application/x-perfmon" ,
  ".pmc":"application/x-perfmon" ,
  ".pmd":"application/x-pmd" ,
  ".pml":"application/x-perfmon" ,
  ".pmr":"application/x-perfmon" ,
  ".pmw":"application/x-perfmon" ,
  ".png":"image/png" ,
  ".pnm":"image/x-portable-anymap" ,
  ".pnz":"image/png" ,
  ".pot,":"application/vnd.ms-powerpoint" ,
  ".ppm":"image/x-portable-pixmap" ,
  ".pps":"application/vnd.ms-powerpoint" ,
  ".ppt":"application/vnd.ms-powerpoint" ,
  ".pptx":"application/vnd.openxmlformats-officedocument.presentationml.presentation" ,
  ".pqf":"application/x-cprplayer" ,
  ".pqi":"application/cprplayer" ,
  ".prc":"application/x-prc" ,
  ".prf":"application/pics-rules" ,
  ".prop":"text/plain" ,
  ".proxy":"application/x-ns-proxy-autoconfig" ,
  ".ps":"application/postscript" ,
  ".ptlk":"application/listenup" ,
  ".pub":"application/x-mspublisher" ,
  ".pvx":"video/x-pv-pvx" ,
  ".qcp":"audio/vnd.qcelp" ,
  ".qt":"video/quicktime" ,
  ".qti":"image/x-quicktime" ,
  ".qtif":"image/x-quicktime" ,
  ".r3t":"text/vnd.rn-realtext3d" ,
  ".ra":"audio/x-pn-realaudio" ,
  ".ram":"audio/x-pn-realaudio" ,
  ".rar":"application/octet-stream" ,
  ".ras":"image/x-cmu-raster" ,
  ".rc":"text/plain" ,
  ".rdf":"application/rdf+xml" ,
  ".rf":"image/vnd.rn-realflash" ,
  ".rgb":"image/x-rgb" ,
  ".rlf":"application/x-richlink" ,
  ".rm":"audio/x-pn-realaudio" ,
  ".rmf":"audio/x-rmf" ,
  ".rmi":"audio/mid" ,
  ".rmm":"audio/x-pn-realaudio" ,
  ".rmvb":"audio/x-pn-realaudio" ,
  ".rnx":"application/vnd.rn-realplayer" ,
  ".roff":"application/x-troff" ,
  ".rp":"image/vnd.rn-realpix" ,
  ".rpm":"audio/x-pn-realaudio-plugin" ,
  ".rt":"text/vnd.rn-realtext" ,
  ".rte":"x-lml/x-gps" ,
  ".rtf":"application/rtf" ,
  ".rtg":"application/metastream" ,
  ".rtx":"text/richtext" ,
  ".rv":"video/vnd.rn-realvideo" ,
  ".rwc":"application/x-rogerwilco" ,
  ".s3m":"audio/x-mod" ,
  ".s3z":"audio/x-mod" ,
  ".sca":"application/x-supercard" ,
  ".scd":"application/x-msschedule" ,
  ".sct":"text/scriptlet" ,
  ".sdf":"application/e-score" ,
  ".sea":"application/x-stuffit" ,
  ".setpay":"application/set-payment-initiation" ,
  ".setreg":"application/set-registration-initiation" ,
  ".sgm":"text/x-sgml" ,
  ".sgml":"text/x-sgml" ,
  ".sh":"application/x-sh" ,
  ".shar":"application/x-shar" ,
  ".shtml":"magnus-internal/parsed-html" ,
  ".shw":"application/presentations" ,
  ".si6":"image/si6" ,
  ".si7":"image/vnd.stiwap.sis" ,
  ".si9":"image/vnd.lgtwap.sis" ,
  ".sis":"application/vnd.symbian.install" ,
  ".sit":"application/x-stuffit" ,
  ".skd":"application/x-Koan" ,
  ".skm":"application/x-Koan" ,
  ".skp":"application/x-Koan" ,
  ".skt":"application/x-Koan" ,
  ".slc":"application/x-salsa" ,
  ".smd":"audio/x-smd" ,
  ".smi":"application/smil" ,
  ".smil":"application/smil" ,
  ".smp":"application/studiom" ,
  ".smz":"audio/x-smd" ,
  ".snd":"audio/basic" ,
  ".spc":"application/x-pkcs7-certificates" ,
  ".spl":"application/futuresplash" ,
  ".spr":"application/x-sprite" ,
  ".sprite":"application/x-sprite" ,
  ".sdp":"application/sdp" ,
  ".spt":"application/x-spt" ,
  ".src":"application/x-wais-source" ,
  ".sst":"application/vnd.ms-pkicertstore" ,
  ".stk":"application/hyperstudio" ,
  ".stl":"application/vnd.ms-pkistl" ,
  ".stm":"text/html" ,
  ".svg":"image/svg+xml" ,
  ".sv4cpio":"application/x-sv4cpio" ,
  ".sv4crc":"application/x-sv4crc" ,
  ".svf":"image/vnd" ,
  ".svg":"image/svg+xml" ,
  ".svh":"image/svh" ,
  ".svr":"x-world/x-svr" ,
  ".swf":"application/x-shockwave-flash" ,
  ".swfl":"application/x-shockwave-flash" ,
  ".t":"application/x-troff" ,
  ".tad":"application/octet-stream" ,
  ".talk":"text/x-speech" ,
  ".tar":"application/x-tar" ,
  ".taz":"application/x-tar" ,
  ".tbp":"application/x-timbuktu" ,
  ".tbt":"application/x-timbuktu" ,
  ".tcl":"application/x-tcl" ,
  ".tex":"application/x-tex" ,
  ".texi":"application/x-texinfo" ,
  ".texinfo":"application/x-texinfo" ,
  ".tgz":"application/x-compressed" ,
  ".thm":"application/vnd.eri.thm" ,
  ".tif":"image/tiff" ,
  ".tiff":"image/tiff" ,
  ".tki":"application/x-tkined" ,
  ".tkined":"application/x-tkined" ,
  ".toc":"application/toc" ,
  ".toy":"image/toy" ,
  ".tr":"application/x-troff" ,
  ".trk":"x-lml/x-gps" ,
  ".trm":"application/x-msterminal" ,
  ".tsi":"audio/tsplayer" ,
  ".tsp":"application/dsptype" ,
  ".tsv":"text/tab-separated-values" ,
  ".ttf":"application/octet-stream" ,
  ".ttz":"application/t-time" ,
  ".txt":"text/plain" ,
  ".uls":"text/iuls" ,
  ".ult":"audio/x-mod" ,
  ".ustar":"application/x-ustar" ,
  ".uu":"application/x-uuencode" ,
  ".uue":"application/x-uuencode" ,
  ".vcd":"application/x-cdlink" ,
  ".vcf":"text/x-vcard" ,
  ".vdo":"video/vdo" ,
  ".vib":"audio/vib" ,
  ".viv":"video/vivo" ,
  ".vivo":"video/vivo" ,
  ".vmd":"application/vocaltec-media-desc" ,
  ".vmf":"application/vocaltec-media-file" ,
  ".vmi":"application/x-dreamcast-vms-info" ,
  ".vms":"application/x-dreamcast-vms" ,
  ".vox":"audio/voxware" ,
  ".vqe":"audio/x-twinvq-plugin" ,
  ".vqf":"audio/x-twinvq" ,
  ".vql":"audio/x-twinvq" ,
  ".vre":"x-world/x-vream" ,
  ".vrml":"x-world/x-vrml" ,
  ".vrt":"x-world/x-vrt" ,
  ".vrw":"x-world/x-vream" ,
  ".vts":"workbook/formulaone" ,
  ".wav":"audio/x-wav" ,
  ".wax":"audio/x-ms-wax" ,
  ".wbmp":"image/vnd.wap.wbmp" ,
  ".wcm":"application/vnd.ms-works" ,
  ".wdb":"application/vnd.ms-works" ,
  ".web":"application/vnd.xara" ,
  ".wi":"image/wavelet" ,
  ".wis":"application/x-InstallShield" ,
  ".wks":"application/vnd.ms-works" ,
  ".wm":"video/x-ms-wm" ,
  ".wma":"audio/x-ms-wma" ,
  ".wmd":"application/x-ms-wmd" ,
  ".wmf":"application/x-msmetafile" ,
  ".wml":"text/vnd.wap.wml" ,
  ".wmlc":"application/vnd.wap.wmlc" ,
  ".wmls":"text/vnd.wap.wmlscript" ,
  ".wmlsc":"application/vnd.wap.wmlscriptc" ,
  ".wmlscript":"text/vnd.wap.wmlscript" ,
  ".wmv":"audio/x-ms-wmv" ,
  ".wmx":"video/x-ms-wmx" ,
  ".wmz":"application/x-ms-wmz" ,
  ".wpng":"image/x-up-wpng" ,
  ".wps":"application/vnd.ms-works" ,
  ".wpt":"x-lml/x-gps" ,
  ".wri":"application/x-mswrite" ,
  ".wrl":"x-world/x-vrml" ,
  ".wrz":"x-world/x-vrml" ,
  ".ws":"text/vnd.wap.wmlscript" ,
  ".wsc":"application/vnd.wap.wmlscriptc" ,
  ".wv":"video/wavelet" ,
  ".wvx":"video/x-ms-wvx" ,
  ".wxl":"application/x-wxl" ,
  ".x-gzip":"application/x-gzip" ,
  ".xaf":"x-world/x-vrml" ,
  ".xar":"application/vnd.xara" ,
  ".xbm":"image/x-xbitmap" ,
  ".xdm":"application/x-xdma" ,
  ".xdma":"application/x-xdma" ,
  ".xdw":"application/vnd.fujixerox.docuworks" ,
  ".xht":"application/xhtml+xml" ,
  ".xhtm":"application/xhtml+xml" ,
  ".xhtml":"application/xhtml+xml" ,
  ".xla":"application/vnd.ms-excel" ,
  ".xlc":"application/vnd.ms-excel" ,
  ".xll":"application/x-excel" ,
  ".xlm":"application/vnd.ms-excel" ,
  ".xls":"application/vnd.ms-excel" ,
  ".xlsx":"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" ,
  ".xlt":"application/vnd.ms-excel" ,
  ".xlw":"application/vnd.ms-excel" ,
  ".xm":"audio/x-mod" ,
  ".xml":"text/plain",
  ".xml":"application/xml",
  ".xmz":"audio/x-mod" ,
  ".xof":"x-world/x-vrml" ,
  ".xpi":"application/x-xpinstall" ,
  ".xpm":"image/x-xpixmap" ,
  ".xsit":"text/xml" ,
  ".xsl":"text/xml" ,
  ".xul":"text/xul" ,
  ".xwd":"image/x-xwindowdump" ,
  ".xyz":"chemical/x-pdb" ,
  ".yz1":"application/x-yz1" ,
  ".z":"application/x-compress" ,
  ".zac":"application/x-zaurus-zac" ,
  ".zip":"application/zip" ,
  ".json":"application/json"
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值