nodejs本地搭建一个服务器初级

简单的服务器搭载

先把js文件代码拷贝下:

var http = require('http')                     //这里用node.js的一个内置模块叫http。
//用require去加载这个模块。这个模块就是个对象平台,提供了方法。
http.createServer(function(req,res){
     ,,,,,,,,,,,,,,
})                   //创建服务器,这里有个回调,server函数内部实际上就是个异步的过程,
//内部会创建一个服务器,创建好之后,它会把里面的function的那个函数作为对应的参数来处理我们的请求。
//换句话说,创建好服务器后,当我通过浏览器访问这个服务器时,
//请求底层会被封装成一个对象,对象就是这里的req参数,请求信息都在这个对象里。
//通过req获取用户相关信息,IP,域名,访问信息,,,
//res服务器返回给浏览器的信息,这么一个对象。
例子:
var http =require('http')
var server = http.createServer(function(req,res){
    res.write('hello world')            //发给浏览器的http内容
     res.end()                        //结束了
})
server.listen(9000)      //创建这个服务器后,用.listen这个方法去启动这个服务器,去监听9000这个端口。

如何去运行它?打开终端,当前目录下,输入node 文件名启动。启动后发现页面进入空白地方,输入也没用了。

如图

这时候怎么办?直接在浏览器输入loccalhost:9000访问。如图

这时候看到hello world了。那localhost是什么?它是浏览器的一个host的配置,当你去请求一个域名,中间发生了什么,其中有一步就是通过你的域名去搜索IP地址的这个过程,因为localhost在我们本地做了设置,对应的是127.0.0.1,也就是我本机的IP地址,所以这个请求到了我的本机,然后到了我本机服务器上的9000这个端口了。
这个时候,就相当于这个请求到达我们刚刚启动的服务器了。这个服务器里面,就会进入页面的逻辑,进入到那个回调的函数里,然后再在回调函数里加一条:

var http =require('http')
var server = http.createServer(function(req,res){
    console.log(req)
    res.write('hello world')
    res.end()
})
server.listen(9000)

这时候,关掉终端,再重新来一次,这时候看到终端出现了很多很多的信息,如图

这些都是req对象的信息。这里提醒下,代码里仍然可以用console.log(),结果展示在终端。
比如:

var http =require('http')
http.createServer(function(req,res){
        console.log('hellojirengu')
       res.write('hello world')
        res.end() 
})

如图

现在我们就写了一个简单的服务器了。res.write()是把数据放到响应体里了,当成内容去展示了。响应体就是html文件数据内容。

请求时有个头部,是浏览器自动加的,请求到了服务器后,就进入到了我们的回调函数,进去后,这中间服务器什么都没做,发了一个res.write()的响应,响应头里什么都没加,响应体里就是那个hello world了。如图

这就是网站后台的基本逻辑:不管多么复杂,本质都是这样的,一个请求到了服务器,服务器接收然后处理,再发给浏览器,浏览器处理。那为什么不同的URL打开不同的页面?到了服务器里,根据不同的URL执行不同的逻辑,进行不同的操作,然后返回不同的数据。
假设我这个机器想运行多个网站怎么办呢?

就需要启动多个服务器,每个服务器用不同的端口。比如说,现在这个服务器用的9000端口,再去启动一个,这个端口就不能用了,只能换一个新端口。比如现在重新开一个终端,,,

报错说9000端口被用了,不能开启。只能关掉了。

细化扩展

设置响应头

通过res.setHeader()设置。

var http= require('http')
var server = http.createServer(function(req,res){
      console.log('hahaha')
      res.setHeader('content-type','text/plain;charset=gbk')
//告诉浏览器,返回的数据,你当成字符串就可以了,用gbk去解码。
//这个解码方式权重更高,因为这时候html文件还没解析到里面的charset的设置呢。
      res.write('hello world')
      res.end()
})
server.listen(9000)

响应头内容:如图

Response Header内容就是,可以设置很多东西,这里多了一个content-type。
这时候,把res.write()的内容改一下

var http =require('http')
var server = http.createServer(function(req,res){
    res.setHeader('content-type','text/plain;charset=gbk')
    res.write('<h1>haha</h1>')
    console.log('hellojirengu')
    res.end()
})
server.listen(9000)

如图

content-type='text/plain'就是告诉浏览器,收到数据后当成字符串就行了。

var http =require('http')
var server = http.createServer(function(req,res){
    res.setHeader('content-type','text/html;charset=gbk')
    res.write('<h1>haha</h1>')
    console.log('hellojirengu')
    res.end()
})
server.listen(9000)

再试试,如图

这就是http协议中的响应头的作用,告诉浏览器发送的响应体数据是什么,怎么处理。同理,如果是CSS就当成css去解析。如图

charset=gbk有什么用?这里没中文,改一下:

var http =require('http')
var server = http.createServer(function(req,res){
    res.setHeader('content-type','text/html;charset=gbk')
    res.write('<h1>哈哈</h1>')
    console.log('hellojirengu')
    res.end()
})
server.listen(9000)
//这时候浏览器被服务器通知用gbk解码,所以乱码了。

如图

改成charset=utf-8,就如图

所以如果打开网页出现乱码,或者就是算html中meat没有设置,也可以在服务器响应层面去设置的。
这里要明白了,ajax发的请求是请求,毕竟是请求,服务器也不是人,不智能,服务器的响应也是独立的,不是必须要严格符合请求的,而是尽可能地揣测请求。

var path = require('path')
var fs = require('fs')
var url = require('url')

var router = {
'/getData': function(req, res){
var pathObj = url.parse(req.url, true)

  var page = pathObj.query.page
  var result

  if(page == 1){
   result = [1,2,3]
  }
  if(page == 2){
    result = [4,5,6]
  }
  
  res.write(JSON.stringify(result))
  res.end()    

},
'/hello': function(req, res){
res.end('hello world')
}
}

再深究一下:

var http =require('http')
var server = http.createServer(function(req,res){
   setTimeout(function(){
        res.setHeader('content-type','text/html;charset=utf-8')
        res.writeHead(200,'haha')
        res.write('<html><head><meta charset="gbk" /></head>')
         res.write('<body>')
         res.write('<h1>哈哈<h1>')
         res.write('</body>')
         res.write('</html>')
         res.end()
   },2000)
})
console.log('open http://localhost:8080 ')
server.listen(8080)

运行一下,如图

查看一下,如图

网页源代码

通过res.write()的方式写的。只有end的时候,才会结束传输。所以最后看到了全部信息。

那 res.writeHead(200,'haha')有什么意思呢?如图
中的Status Code选项就是。状态码就是这样设置的。200到300是成功的,300到400类似于做重定向相关的,400到500是文件问题,500,502,503代表服务器执行过程中出错了。

只要打开网站,200就表示成功的,为什么呢?规定是这样的。比如现在把200改成404,就会发生奇怪的事情。如图

网页也打开了,事实上是运行没错误,但是出现了404,就报告用户错了,因为404的出现会触发一系列的后续事件,比如报错,颜色红色等。同理,503也会如此,所以,以后设置时,尽量遵循规则设定,以免歧义误导。
为什么没有乱码?因为浏览器先听服务器的解码方式去解码,响应头的数据就是解析依据,响应体就是数据来源,一堆字符串。如果响应头没设置,就再从html中找。

到这里就是把服务器基本原理介绍了,但是这个服务器太简陋了,下面讲真正有普适意义的服务器。

静态服务器

有个点是可以向服务器要html文件和外部加载的文件资源。
换句话说,我们把代码放到一个文件夹里,然后把网站部署到远程的机器上,然后通过终端执行node 服务器文件,开启这个服务器,那网站内容就可以访问了。那他如何访问到的?且看一看!

如图
html,css,js,img文件都放到static文件夹里了,server.js是服务器文件。
server.js代码:
var http = require('http')           //又多了几个模块
var path = require('path')       //处理URL的模块,文件路径的写法在windows或者linux上不一样,会自动识别
var fs = require('fs')         //读写文件的,都数据,写数据
var url = require('url')      //自动解析URL,并得到信息,相当于在控制台用location,不用再用正则去提取。


function staticRoot(staticPath, req, res){
  
  var pathObj = url.parse(req.url, true)
  
  /*
  if(pathObj.pathname === '/'){
    pathObj.pathname += 'index.html'
  }
  */

  var filePath = path.join(staticPath, pathObj.pathname)
  
  var fileContent = fs.readFileSync(filePath,'binary')
  res.write(fileContent, 'binary')
  res.end()
  
  /*
  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.write(fileContent, 'binary')
      res.end()      
    }
  })
  */

}
//首先看这里是创建服务器的,再侦听8080端口。
var server = http.createServer(function(req, res){
  staticRoot(path.join(__dirname, 'static'), req, res)
})
//当请求到来后,进入了里面的回调函数,后面一堆是处理请求,写了个staticRoot函数,函数功能就是把一个路径当成静态文件路径,然后再把req,res传进去,再把路径名传进去。
//__dirname是nodejs里面的一个内置变量,直接可用,代表当前的server.js文件,通过方法得到step1的绝对路径。 
 //'static'指的就是图里面的那个static文件夹。方法得到static的路径。
//两个路径作用后生成一个static的绝对路径。为什么不直接写绝对路径,可能我的文件过几天会改变位置。再一个,代码在各种系统里通用。

server.listen(8080)
console.log('visit http://localhost:8080' )

这个静态服务器如何实现的?
比如说用户访问localhost:8080/index.html的时候,如何让用户看到这个static里面的文件呢?这个请求因为localhost:8080肯定是到了我们这个服务器了。服务器收到请求后,进入了。
var server = http.createServer(function(req, res){
staticRoot(path.join(__dirname, 'static'), req, res)
})
server.listen(8080)这个函数里面,然后该怎么办呢?
是不是通过req得到当前的URL?对吧。得到URL,就可以得到后面的这个后缀:/index.html,只要在本地读取到对应的static下面找到这个文件,把文件内容读出来,读出来之后当成字符串发给浏览器。告诉浏览器,这是html,浏览器就当成html解析,解析后,看到了加载css,js,图片的路径,就会重新组装新的URL,发给服务器,服务器再来一遍,把文件路径确定,读取,再发送。

把文件放到这个文件夹下,通过URL就能访问到,这就是静态服务器。
所以说,关键就是服务器的文件位置,还有html文件的位置了。服务器有什么功能,自己就要去实现什么功能。
还有一些其他的懒人版的成品服务器,就无所谓啦。

测试一下,运行代码是:

var http = require('http')
var path = require('path')
var fs = require('fs')
var url = require('url')


function staticRoot(staticPath, req, res){
  console.log(staticPath)
  console.log(req.url)
  var pathObj = url.parse(req.url, true)
  console.log(pathObj)              //看下面的截图结果。

  var filePath = path.join(staticPath, pathObj.pathname)
//静态路径到了static了,现在再加上这个pathname,得到了请求文件的绝对路径了。然后用下面的fs方法读取。

/* var fileContent = fs.readFileSync(filePath,'binary')
  res.write(fileContent, 'binary')
  res.end()
  */                //readFileSync同步读取的方法,读完文件得到 fileContent这个东西。再写出去。

fs.readFile(filePath, 'binary', function(err, fileContent){
    if(err){                              //这个是readFile异步读取,'binary'是二进制方式读取,
//有时候读的不光是字符串,对于图片,文件也希望服务器支持,换成二进制就行了。
      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()      //这里有个疑问,没有给浏览器发送数据解析的标准,没有设置content-type啊。
//这里因为文件后缀index.html会被浏览器辨识,有一定的约定了,当成html文件。a.css也是一样的,虽然响应体里,发请求时,后缀是.css,自动认为是css去解析,同理图片也是一样的。
    }
  })
 

}

var server = http.createServer(function(req, res){
  staticRoot(path.join(__dirname, 'static'), req, res)
})

server.listen(8080)
console.log('visit http://localhost:8080' )

终端console.log()结果,如图

得到了那个绝对位置了。有了这个绝对路径才可以读文件啊。
图里也知道了req.url=/index.html。得到了它,就进行解析,

同理,第二个请求发过来后,如图:
得到,req.url=/css/a.css。
同理,第三个是req.url=/img/logo.png,,,

这里的pathname是最不会出错的,要它就可以了,判断路径时url.parse这个对象很重要。这里再加一段代码:

if(pathObj.pathname === '/'){
    pathObj.pathname += 'index.html'
  }           //如果pathname=/,就表示,这时候的pathname自己加了下,变成/index.html了,
//如果这时候访问http://localhost:8080/等同于后面加了index.html,直接可访问到文件。
//也就是端口的默认文件。

这是服务器找不到文件的图

总结一下吧,搭建服务器,首先是创建,参数有三个,一个是路径,这里指的是请求文件的绝对路径;

一个是请求,请求的一些属性可以帮助得到文件路径;
一个是响应,响应重在反馈,重在设置,设置内容的类型,解码方式,进程的反馈,写内容。
而浏览器只是发请求那个对象和接收数据解析,服务器是接收请求,处理,并找资源,并按设置把响应体和响应头发过去。通过URL的域名定位服务器,通过端口定位。
服务器通过路径得到文件位置。
最简单的逻辑,当然容易挂,不健壮,代码如下:

var http = requirt('http')
var fs = requirt('fs')
var server =http.createServer(function(req,res){
    var fileContent = fs.readFileSync(__dirname +'/static' + req.url,'binary')         
  //这是已经知道文件间的相互位置,干的。__dirname直接得server.js的绝对路径,加那两个就得到了嘛。
    res.write(fileContent,'binary')
    res.end()
})
server.listen(8080)
console.log('visit http://localhost:8080')

下面就防止服务器崩了的。

var http = requirt('http')
var fs = requirt('fs')
var server =http.createServer(function(req,res){
   try{
         var fileContent = fs.readFileSync(__dirname +'/static' + req.url,'binary')
    res.write(fileContent,'binary')
}catch(e){
      res.writeHead(404,'not found')
}

    res.end()
})
server.listen(8080)
console.log('visit http://localhost:8080')

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

推荐阅读更多精彩内容