使用原生NodeJs搭建服务器

414 阅读16分钟

如何使用原生NodeJs搭建服务器?

一、初始化一个空白的项目

打开vscode编辑器,打开终端面板,输入npm inint -y 初始化一个项目,然后新建一个app.js的文件,开始淦。

二、如何通过原生的NodeJs搭建web服务器?

具体步骤:

1、导入http模块

2、通过http模块创建服务对象

3、通过服务对象监听用户请求

4、指定监听的端口号

通过以上4步便可创建一个最简单的web服务器了,具体代码实现:

// app.js文件
// 1、导入http模块
const http = require('http');

// 2、通过http模块创建服务对象
const server = http.createServer();

// 3、通过服务对象监听用户请求
server.on('request', (req, res) => {
    console.log('接收到了浏览器的请求');
});

// 4、指定监听的端口号
server.listen(3000);

我们在终端面板输入node app.js便可运行服务器,之后打开浏览器在地址栏中输入localhost:3000回车,便可在vscode终端面板中看到打印的==“接收到了浏览器的请求”==,说明我们的服务器创建成功了。服务器的功能远没有这么简单,下面让我们看下如何处理用户的请求。

三、处理 get 和 post 请求

要处理用户的getpost请求,首先我们需要获取到用户的请求方式。那么如何获取到用户的请求方式呢?我们在上面创建web服务器的第3步,通过服务对象监听用户请求时,我们传入了一个回调函数,它接收两个参数reqres,第一个参数reqrequest的简写),它是是请求对象,里面包含了用户的请求信息,第二个参数resresponse的简写)则是响应对象,里面包含了我们要发送给客户端的信息。知道了这个之后,我们便可从res请求对象中拿到我们想要的请求方式。

// 3、通过服务对象监听用户请求
server.on('request', (req, res) => {
  // 获取请求类型,并转为小写
  let method = req.method.toLowerCase();
  console.log(method);
});

我们再次重启项目,在浏览器中访问localhost:3000便可在vscode终端面板中看到打印的get,说明此次请求是get请求,那么我们如何测试一下post请求呢?我们知道浏览器内没法直接发送post请求,那怎么办呢?我们可以借助一个网络请求调试工具:postman,大家可以自行安装这个工具,在这里我给大家推荐一个更好用的方式,在vscode编辑器中我们安装一个Postcode的插件,我们便可直接在vscode中调试各种类型的请求了,简直不要太方便。通过测试post请求肯定也是没有问题的。

拿到请求方式后我们便可对具体的请求进行对应的逻辑处理了。

// 3、通过服务对象监听用户请求
server.on('request', (req, res) => {
  // 获取请求类型,并转为小写
  let method = req.method.toLowerCase();
  console.log(method);
  
  if (method === 'get') {
      console.log('处理get请求');
  }else if(method === 'post'){
      console.log('处理post请求');
  }
});

四、如何处理不同路径(不同路由)的请求?

要处理不同路径(不同路由)的请求,和上面处理 get 和 post 请求一样,我们首先要获取到请求的路径,然后根据路径的不同来进行相应的处理。

// 3、通过服务对象监听用户请求
server.on('request', (req, res) => {
  // 获取请求类型,并转为小写
  let method = req.method.toLowerCase();
  console.log(method);
  
  // 获取请求路径,比如:/login?name=admin&pwd=123456
  let url = req.url;
  // 解析获取到的请求路径
  let path = url.split("?")[0];
  if (method === 'get') {
      console.log('处理get请求');
      // 获取请求参数
      let params = url.split("?")[1];
      // 具体的业务处理
      if(path === '/login'){
          console.log('处理登录请求');
      }else if(path === '/register'){
          console.log('处理注册请求');
      }
  }else if(method === 'post'){
      console.log('处理post请求');
      // 具体的业务处理
      if(path === '/login'){
          console.log('post处理登录请求');
      }else if(path === '/register'){
          console.log('post处理注册请求');
      }
  }
});

五、如何获取(处理)请求参数?

get请求的请求参数是和url拼接在一起的,而post请求的请求参数一般是放在请求体body里的。所以接下来我们分别获取一下这两种请求方式的请求参数。

获取get请求参数,在上面我们获取请求路径时,获取成功后,通过?对路径进行了分割处理,?前面的部分是路径,?后面的部分是请求参数。但是获取到的请求参数是字符串形式不方便我们处理,比如:name=admin&pwd=123456,我们希望拿到的参数是一个对象形式的,比如:{name: 'admin', pwd: '123456'},这样我们处理请求参数时就方便很多了,那么如何解析成对象形式呢?我们可以借助NodeJs中的querystring模块来帮助我们解析。

// 首先在app.js中引入querystring模块
const queryString = require('querystring');

// 3、通过服务对象监听用户请求
server.on('request', (req, res) => {
  // 获取请求路径,比如:/login?name=admin&pwd=123456
  let url = req.url;
  // 解析获取到的请求路径
  let path = url.split("?")[0];
  if (method === 'get') {
      console.log('处理get请求');
      // 获取请求参数
      let params = url.split("?")[1];
      // 将字符串请求参数解析为对象形式
      params = queryString.parse(params);
  }else if(method === 'post'){
      console.log('处理post请求');
  }
});

获取post请求参数,post请求的请求参数一般是放在请求体body里的,我们要获取到body的数据,需要监听reqdata事件,在这个事件里面,我们将接收到参数信息进行拼接,当参数信息接收完毕时,会触发reqend事件。

// 首先在app.js中引入querystring模块
const queryString = require('querystring');

// 3、通过服务对象监听用户请求
server.on('request', (req, res) => {
  // 获取请求路径,比如:/login?name=admin&pwd=123456
  let url = req.url;
  // 解析获取到的请求路径
  let path = url.split("?")[0];
  let params = '';
  if (method === 'get') {
      console.log('处理get请求');
      // 获取请求参数
      params = url.split("?")[1];
      // 将字符串请求参数解析为对象形式
      params = queryString.parse(params);
  }else if(method === 'post'){
      console.log('处理post请求');
      // post接收参数片段
      req.on('data', (chuck) => {
        params += chuck;
      });
      // 接收参数结束事件
      req.on('end', (chuck) => {
          // 解析请求参数
          params = queryString.parse(params);
          console.log(params);
      });
  }
});

六、如何返回客户端数据?

我们到目前为止已经可以对不同请求方式、不同的请求路径以及请求参数进行处理了,那么服务器处理完具体的业务逻辑后,就该给客户端响应了,那么服务器如何响应客户端呢?res响应对象就该派上用场了。

响应客户端步骤:

1、告诉客户端返回的数据是什么类型

2、告诉客户端返回的数据是什么

3、指定字符编码

// 首先在app.js中引入querystring模块
const queryString = require('querystring');

// 3、通过服务对象监听用户请求
server.on('request', (req, res) => {
  // 获取请求路径,比如:/login?name=admin&pwd=123456
  let url = req.url;
  // 解析获取到的请求路径
  let path = url.split("?")[0];
  let params = '';
  if (method === 'get') {
      console.log('处理get请求');
      // 获取请求参数
      params = url.split("?")[1];
      // 将字符串请求参数解析为对象形式
      params = queryString.parse(params);
      // 具体的业务处理
      if(path === '/login'){
          console.log('处理登录请求');
          // 1、告诉客户端返回的数据是什么类型,如果返回数据中有中文还要指定字符编码格式,否则会乱码
          res.writeHead(200, {
            // 'Content-Type': 'text/plain; charset=utf-8;' // 返回文本类型
            'Content-Type': 'application/json;' // 返回Json类型
          })
          // 2、告诉客户端返回的数据是什么
          // res.end('Hellow World NodeJs! 你好!');
          res.end(JSON.stringify({
            name: '小笑残虹',
            age: 18
          }));
      }else if(path === '/register'){
          console.log('处理注册请求');
      }
  }else if(method === 'post'){
      console.log('处理post请求');
      // post接收参数片段
      req.on('data', (chuck) => {
        params += chuck;
      });
      // 接收参数结束事件
      req.on('end', (chuck) => {
          // 解析请求参数
          params = queryString.parse(params);
          console.log(params);
      });
  }
});

七、返回静态资源

上面我们服务器已经可以返回文本和json数据了,接下来我们就要返回服务器的静态资源了,比如图片、音频、视频、HTML文件等等。

我们可以封装一个工具类来专门处理静态资源,我们新建staticServer.js文件,具体逻辑请看代码:

const path = require('path');
const fs = require('fs');
const mime = require('./mime.json');

/**
 * 读取静态资源
 * @param req 请求对象
 * @param res 响应对象
 * @param rootPath 静态资源所在的目录   
 */
function readFile(req, res, rootPath) {
  // 1、获取静态资源地址
  // http://127.0.0.1:3000/login.html?username=xxch&password=123456;
  let fileName = req.url.split('?')[0];
  let filePath = path.join(rootPath, fileName);
  console.log(filePath);
  // 2、判断静态资源是否存在
  let isFxists = fs.existsSync(filePath);
  if (!isFxists) {
    return;
  }
  // 3、获取静态资源的后缀名
  let fileExt = path.extname(filePath);
  // 4、根据文件的后缀获取对应的类型
  let type = mime[fileExt];
  // 5、对文本类型进行特殊的处理,指定编码格式
  if (type.startsWith('text')) {
    type += '; charset=utf-8';
  }
  // 6、告诉客户端返回数据的类型
  res.writeHead(200, {
    'Content-Type': type
  });
  // 7、加载静态资源并返回静态资源
  fs.readFile(filePath, (err, content) => {
    if (err) {
      res.end('Server Error');
      return
    }
    res.end(content);
  })
}

module.exports = {
  readFile
}

这里需要一个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"
}

八、如何返回动态数据(动态网页)

返回动态数据(动态网页),我们可以借助模板引擎来实现,比如ejs模板引擎等等。

首先安装ejs模板引擎npm install ejs

为了方便使用ejs模板引擎,同样我们封装成一个独立的模块,我们新建一个dynamicServer.js文件,具体逻辑代码如下:

const ejs = require('ejs');

function renderHTML(req, res, fileName) {
  ejs.renderFile(fileName, req.data, function (err, str) {
    res.writeHead(200, {
      'Content-Type': 'text/html; charset=utf-8;'
    });
    res.end(str)
  })
}

module.exports = {
  renderHTML
}

至此,一个简单的基本的服务器已经搭建完成了,下面是app.js的完整代码:

// 1、导入http模块
const http = require('http');
const queryString = require('querystring');
const path = require('path');
const rootPath = path.join(__dirname, 'www');
// 返回静态资源
const staticServer = require('./staticServer');
// 返回动态网页
const dynamicServer = require('./dynamicServer');

// 2、通过http模块创建服务对象
const server = http.createServer();
// 3、通过服务对象监听用户请求
server.on('request', (req, res) => {
  // 处理静态资源
  staticServer.readFile(req, res, rootPath);
  // console.log('接收到了浏览器的请求');
  // console.log('请求路径:', req.url);  // /login?userName=xxch&password=123456
  // 1、获取请求路径
  let url = req.url;
  // 2、获取请求类型
  let method = req.method.toLowerCase();
  console.log(method);
  // 解析获取到的请求路径
  let path = url.split("?")[0];
  // 3、获取请求参数
  let params = '';
  if (method === 'get') {
    params = url.split("?")[1];
    // 将字符串解析为对象
    params = queryString.parse(params);
    if (path === '/login') {
      console.log('处理登录请求', path, params);
      // 1、告诉客户端返回的数据是什么类型,如果返回数据中有中文还要指定字符编码格式,否则会乱码
      res.writeHead(200, {
        // 'Content-Type': 'text/plain; charset=utf-8;' // 返回文本类型
        'Content-Type': 'application/json;' // 返回Json类型
      })
      // 2、告诉客户端返回的数据是什么
      // res.end('Hellow World NodeJs! 你好!');
      res.end(JSON.stringify({
        name: '小笑残虹',
        age: 18
      }));
    } else if (path === '/register') {
      console.log('处理注册请求', path, params);
      let data = {
        msg: '我是动态数据'
      }
      req.data = data;
      dynamicServer.renderHTML(req, res, './views/index.html');
    }
  } else if (method === 'post') {
    console.log('处理post请求');
    // post接收参数片段
    req.on('data', (chuck) => {
      params += chuck;
    })
    // 接收参数结束事件
    req.on('end', (chuck) => {
      // 解析请求参数
      params = queryString.parse(params);

      if (path === '/login') {
        console.log('post处理登录请求', path, params);
      } else if (path === '/register') {
        console.log('post处理注册请求', path, params);
      }
    })
  }
})
// 4、指定监听的端口号
server.listen(3000);