使用nodejs服务器路由解析

上次学到的是简单的服务器,静态服务器,假设我想实现功能更复杂的服务器,比如说URL不止是定位一个文件,而是可以得到任何数据,或者说mock一些数据和前端进行交互,就需要复杂点的服务器了。
先来个最精简的代码:

var http = require('http')    
var fs = require('fs')           //用了上面两个模块
http.createServer(function(req,res){         //创建一个server,返回的是一个server对象,对象直接侦听8080端口。
      switch(req.url){                     //请求到了,需要处理对应的路由,路由就是localhost:8080这个域名后面的那一堆东西。路由的本质是后端根据路由去做对应的事情。
          case '/getWeather':                //req.url=/getWerther,发送JSON数据,并变成字符串
              res.end(JSON.stringify({a:1,b:2}))
               break;              //停掉,这个相当于mock数据了
       case '/user/123':
            res.end(fs.readFileSync(__dirname + '/static/user.123'))                 //读这个文件,这个文件是什么不重要,记得路径能读到文件这个道理就行。
            break;
          default:             //这两个都没匹配上,就认为是个静态文件
            res.end(fs.readFileSync(__dirname + '/static' + req.url))   
}
}).listen(8080)   //当请求到了,只要是以localhost:8080作为前缀的都会到这个当前服务器上,请求到了。

文件的相对关系如图

static是html等文件数的文件夹。server.js就是服务器文件了,这里要记得__dirname就可以得出它的绝对路径了。
这时候,终端启动一下服务器,然后,具体操作就变得可控了,域名加路由。
我想访问文件就把约定好的文件的路由后缀加上,这个路由不是指路径的时候,就区别于静态服务器了,路由就是自己设置好的指令类似的,就能触发服务器的下一步具体操作。想mock天气数据,路由就改成约定好的那个,想怎样就怎样。当路由都不符合约定的指令了,就当成文件路径,静态服务器的那种操作了。
结合前面学到的ajax,可以自己模拟后端数据,然后做效果了。
假设一个网站没有登录功能,我们就可以用这个实现一个sserver,路由已经不是文件路径了,可以自行设置,然后服务器看到路由,就对应到设置好逻辑的模板上了,读取数据,用模板把数据拼装成字符串,发给前端。

但是它mock数据的时候,还是有瑕疵,我想传递不同的参数返回不同的数据,怎么办?
比如,在JS 文件的代码是:

var xhr = new XMLHttpRequest()
xhr.open('GET',"getWeather?city=beijing",true)
xhr.send()
xhr.onload = function(){
    console.log(JSON.parse(xhr.responseText))
}

再把server的代码改一下:

var http = require('http')    
var fs = require('fs')  
var url = require('url')             //加了URL模块

http.createServer(function(req,res){ 
  
  var pathobj = url.parse(req.url,true)
  console.log(pathobj)       
  //这里主要是在JS文件中的路由改成getweather?city=beijing,看看url的对象里,city=beijing是什么。

      switch(req.url){                   
          case '/getWeather':
              res.end(JSON.stringify({a:1,b:2}))
               break;
       case '/user/123':
            res.end(fs.readFileSync(__dirname + '/static/user.text'))
            break;
          default:
            res.end(fs.readFileSync(__dirname + '/static' + req.url))   
}
}).listen(8080)  

如图:

这个过程是这样的,当发送getWeather?city=beijing这个请求时,设置的前两个路由都匹配不上,就当成本地文件路径处理,也找不到,所以报错了。

但是,我们可以看很多东西,先看看显示的url对象的内容,如图:

换句话说,对于我们的请求,匹配的时候,只要匹配pathname就行了,而不是url,我要得到的是那个query,重要的就是pathname,query了。
这时候,改下代码:
var http = require('http')    
var fs = require('fs')  
var url = require('url')

http.createServer(function(req,res){ 
  
  var pathobj = url.parse(req.url,true)
  console.log(pathobj)

//路由必须=url.pathname
//这里的城市判断就是url.query对象里的city。
      switch(pathobj.pathname){                   
          case '/getWeather':
          var ret
          if(pathobj.query.city=='beijing'){
              ret = {
                city:'beijing',
                weather:'晴天'
              }   
          }else{
            ret={
              city:pathobj.query.city,
              weather:'不知道'
            }
          }
              res.end(JSON.stringify(ret))
               break;
       case '/user/123':
            res.end(fs.readFileSync(__dirname + '/static/user.text'))
            break;
          default:
            res.end(fs.readFileSync(__dirname + '/static' + pathobj.pathname))   
}
}).listen(8080)  

这样就mock了数据了。路由就是需要自己一个一个去设置的。

如图

一个比较完善的服务器代码

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

var routes = {                     //第一部分就是routes,匹配路由或者url的各种情况是key,value就是对应的处理了。
  '/a': function(req, res){
    res.end('match /a, query is:' + JSON.stringify(req.query))
  },

  '/b': function(req, res){
    res.end('match /b')
  },

  '/a/c': function(req, res){
    res.end('match /a/c')
  },

  '/search': function(req, res){
    res.end('username='+req.body.username+',password='+req.body.password)

  }      //通过输入routes[key]得到对应的值

}

//主函数入口:
var server = http.createServer(function(req, res){
  routePath(req, res)       //处理方法
})

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


function routePath(req, res){
  var pathObj = url.parse(req.url, true)    //解析url,   
  console.log(pathObj)
  var handleFn = routes[pathObj.pathname]     //得到路由,从routes里去匹配,
  if(handleFn){                    
    req.query = pathObj.query

  
  //参考 https://nodejs.org/en/docs/guides/anatomy-of-an-http-transaction/
    // post json 解析
    var body = ''
    req.on('data', function(chunk){        //
      body += chunk
    }).on('end', function(){
      req.body = parseBody(body)
      handleFn(req, res)
    })
    
  }else {
    staticRoot(path.resolve(__dirname, 'static'), req, res)
  }       //都匹配不上,当成静态文件处理。
}

function staticRoot(staticPath, req, res){
  var pathObj = url.parse(req.url, true)
  var filePath = path.join(staticPath, pathObj.pathname)
  fs.readFile(filePath,'binary', function(err, content){
    if(err){
      res.writeHead('404', 'haha Not Found')
      return res.end()
    }

    res.writeHead(200, 'Ok')
    res.write(content, 'binary')
    res.end()  
  })

}
//如果匹配上了,就进入这个逻辑。
function parseBody(body){
  var obj = {}
  body.split('&').forEach(function(str){
    obj[str.split('=')[0]] = str.split('=')[1]
  })
  return obj
}

为什么不加端口就能访问

首先域名被购买了,域名本身有作用,在购买域名的网站上,它把域名绑定一个IP,IP 就是服务器地址,发请求,就会发到对应IP上,后面没写端口,就是默认的80端口,80端口到了服务器,这时候在逻辑上又启动了一个服务器,叫代理服务器,请求到了我写的代理服务器上,发现url是它,那我就转发到我当前机器的另外一个端口上,也就是它自己网站所启动的端口,到了它对应端口的服务器上。
上面做了很多例子,都是要输入端口的,这是因为在服务器里没有把域名和IP绑定,设置好了,就可以通过域名直接得到了。而野路子出来的域名没有备案,端口的意思就是防止服务器被好多野路子文件一起占用,到时候一个请求该如何对应一个正确的回应?开一个端口,就是一个使用名额,也更形象为一种约定,分流嘛。

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

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,644评论 18 139
  • 名词延伸 通俗的说,域名就相当于一个家庭的门牌号码,别人通过这个号码可以很容易的找到你。如果把IP地址比作一间房子...
    杨大虾阅读 20,594评论 2 57
  • 1.这篇文章不是本人原创的,只是个人为了对这部分知识做一个整理和系统的输出而编辑成的,在此郑重地向本文所引用文章的...
    SOMCENT阅读 13,053评论 6 174
  • 个人认为,Goodboy1881先生的TCP /IP 协议详解学习博客系列博客是一部非常精彩的学习笔记,这虽然只是...
    贰零壹柒_fc10阅读 5,051评论 0 8
  • 1. 基础知识 1.1 3种常见的计算机体系结构划分 OSI分层(7层):物理层、数据链路层、网络层、传输层、会话...
    Mr希灵阅读 19,864评论 6 120