初涉Node:搭建一个简单的node服务器

文件路径示意:

C:\Users\Administrator\我的文档\HBuilderProject\httpServer


httpServer:
│  app.js
│  
└─HS\
    │  httpServer.html   // 主页面
    │  
    ├─css
    │      test.css
    │      
    ├─imgs
    │      img.jpg 
    │      
    └─js
            test.js        

静态资源内容:

httpServer.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <link rel="stylesheet" href="css/test.css">
</head>
<body>
    <h1>Hello World!</h1>
    <img src="imgs/img.jpg">
</body>
<script src="js/test.js"></script>
</html>
</html>

test.css

h1 {
    color: skyblue;
}

test.js

alert("sss");

img
一张图


静态服务器实现大致思路:

浏览器发送URL,服务端解析URL,对应到硬盘上的文件。如果文件存在,返回200状态码,并发送文件到浏览器端;如果文件不存在,返回404状态码,发送一个404的文件到浏览器端。

app.js
var http = require('http')
var path = require('path')
var fs = require('fs')
var url = require('url')

function staticRoot(staticPath, req, res) {

  console.log("staticPath: " + staticPath);

  console.log("req.url: " + req.url);           // 查看请求URL
  var pathObj = url.parse(req.url, true);
  console.log(pathObj);                         // 使用URL模块的功能函数解析请求URL,得到相关对象

  if (pathObj.pathname === '/') {
    pathObj.pathname += 'httpServer.html'
  }

  var filePath = path.join(staticPath, pathObj.pathname);         // 拼装为各资源文件绝对路径
  // c:\Users\Administrator\我的文档\HBuilderProject\httpServer\HS + ['httpServer.html','/css/test.css','/imgs/img.jpg','/js/test.js']
  console.log("filePath: " + filePath);

  
  fs.readFile(filePath, 'binary', function (err, fileContent) {  
    if (err) {
      console.log('404')
      res.writeHead(404, 'not found')
      res.end('<h1>404 Not Found</h1>')
    } else {
      console.log('ok');
      res.writeHead(200, 'OK');
      res.write(fileContent, 'binary');
      res.end();
    }
  });
  

  console.log("\n");
}

var server = http.createServer(function (req, res) {
  staticRoot(path.join(__dirname, 'HS'), req, res);             // 将其组装成资源文件夹路径
  // c:\Users\Administrator\我的文档\HBuilderProject\httpServer\ + HS
})
server.listen(8080);
console.log('visit http://localhost:8080');

访问localhost:8080,将会进入createServer函数,参数req res包括了浏览器的请求信息和响应信息(head),我们用一个staticRoot函数来接受并处理后续内容。

参数__dirname为app.js所在绝对路径的文件夹。
c:\Users\Administrator\我的文档\HBuilderProject\httpServer
使用join()方法,拼接静态资源内容所在文件夹。
// c:\Users\Administrator\我的文档\HBuilderProject\httpServer\HS

此时,本地服务器便可根据绝对路径找到相关静态文件,发送出去。

接下来需要解析请求URL。
console.log("req.url: " + req.url);
在我们传入staticRoot函数中的req对象包含了许多请求信息,如User-Agent、cookie、accept、host、method.........

QQ截图20180421171034.jpg

url.parse()可以将一个完整的URL地址,分为很多部分,常用的有:host、port、pathname、path、query。

var pathObj = url.parse(req.url, true);

我们可以从req对象里得到用户的请求URL,其实就是文件的路径。

每一次请求的pathObj如下:

'/httpServer.html'
'/css/test.css'
'/imgs/img.jpg'
'/js/test.js'
var filePath = path.join(staticPath, pathObj.pathname);

拼接为绝对路径。

请求URL:
c:\Users\Administrator\我的文档\HBuilderProject\httpServer\HS\httpServer.html
c:\Users\Administrator\我的文档\HBuilderProject\httpServer\HS\css\test.css
c:\Users\Administrator\我的文档\HBuilderProject\httpServer\HS\imgs\img.jpg
c:\Users\Administrator\我的文档\HBuilderProject\httpServer\HS\js\test.js

进入下面的函数。

  fs.readFile(filePath, 'binary', function (err, fileContent) {   // 这个函数只执行了一次
    test++;
    if (err) {
      console.log('404')
      res.writeHead(404, 'not found')
      res.end('<h1>404 Not Found</h1>')
    } else {
      console.log('ok');
      res.writeHead(200, 'OK');
      res.write(fileContent, 'binary');
      res.end();
    }
  });

关于fs模块:

Node.js 文件系统
Node.js——文件系统模块

异步读取时,传入的回调函数接收两个参数,当正常读取时,err参数为nullfileContent参数为读取到的String。当读取发生错误时,err参数代表一个错误对象,fileContentundefined。这也是Node.js标准的回调函数:第一个参数代表错误信息,第二个参数代表结果。

res.writeHead()

向请求的客户端发送响应头。
该函数在一个请求内最多只能调用一次,如果不调用,则会自动生成一个响应头。

response.writeHead(statusCode, [reasonPhrase], [headers])
// statusCode:响应头的状态码,如:200、404等
// reasonPhase:[可选],用于简单说明的字符串。比如:“服务器因为维护暂时无法正常访问....”
// headers:类似关联数组的对象,表示响应头的每个属性
res.write()

向请求的客户端发送响应内容。
在 response.end() 之前,response.write() 可以被执行多次。

response.write(chunk, [encoding])
// chunk:一个buffer 或 字符串,表示发送的内容
// encoding:如果chunk是字符串,就需要指定encoding来说明它的编码方式,默认utf-8
res.end()

结束响应,告诉客户端所有消息已经发送。当所有要返回的内容发送完毕时,该函数必须被调用一次。
如何不调用该函数,客户端将永远处于等待状态

response.end([data], [encoding])
// data:end()执行完毕后要输出的字符,如果指定了 data 的值,那就意味着在执行完 response.end() 之后,会接着执行一条 response.write(data , encoding);
// encoding:对应data的字符编码

所有资源读取返回客户端后,将先弹出对话框,然后显示页面。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,189评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,577评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,857评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,703评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,705评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,620评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,995评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,656评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,898评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,639评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,720评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,395评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,982评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,953评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,195评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,907评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,472评论 2 342

推荐阅读更多精彩内容