美文网首页
使用nodejs服务器路由解析

使用nodejs服务器路由解析

作者: 流着万条永远的河 | 来源:发表于2017-09-22 16:43 被阅读0次

    上次学到的是简单的服务器,静态服务器,假设我想实现功能更复杂的服务器,比如说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绑定,设置好了,就可以通过域名直接得到了。而野路子出来的域名没有备案,端口的意思就是防止服务器被好多野路子文件一起占用,到时候一个请求该如何对应一个正确的回应?开一个端口,就是一个使用名额,也更形象为一种约定,分流嘛。

    相关文章

      网友评论

          本文标题:使用nodejs服务器路由解析

          本文链接:https://www.haomeiwen.com/subject/qqwxextx.html