最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Node.js原生api搭建web服務(wù)器的方法步驟

 更新時(shí)間:2019年02月15日 15:04:42   作者:無心亦逍遙  
這篇文章主要介紹了Node.js原生api搭建web服務(wù)器的方法步驟,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

node.js 實(shí)現(xiàn)一個(gè)簡單的 web 服務(wù)器還是比較簡單的,以前利用 express 框架實(shí)現(xiàn)過『nodeJS搭一個(gè)簡單的(代理)web服務(wù)器』。代碼量很少,可是使用時(shí)需要安裝依賴,多處使用難免有點(diǎn)不方便。于是便有了完全使用原生 api 來重寫的想法,也當(dāng)作一次 node.js 復(fù)習(xí)。

1、靜態(tài) web 服務(wù)器

'use strict' 
 
const http = require('http') 
const url = require('url') 
const fs = require('fs') 
const path = require('path') 
const cp = require('child_process') 
 
const port = 8080 
const hostname = 'localhost' 
 
// 創(chuàng)建 http 服務(wù) 
let httpServer = http.createServer(processStatic) 
// 設(shè)置監(jiān)聽端口 
httpServer.listen(port, hostname, () => {  
 console.log(`app is running at port:${port}`)  
 console.log(`url: http://${hostname}:${port}`) 
 cp.exec(`explorer http://${hostname}:${port}`, () => {}) 
}) 
// 處理靜態(tài)資源 
function processStatic(req, res) {  
 const mime = { 
  css: 'text/css', 
  gif: 'image/gif', 
  html: 'text/html', 
  ico: 'image/x-icon', 
  jpeg: 'image/jpeg', 
  jpg: 'image/jpeg', 
  js: 'text/javascript', 
  json: 'application/json', 
  pdf: 'application/pdf', 
  png: 'image/png', 
  svg: 'image/svg+xml', 
  woff: 'application/x-font-woff', 
  woff2: 'application/x-font-woff', 
  swf: 'application/x-shockwave-flash', 
  tiff: 'image/tiff', 
  txt: 'text/plain', 
  wav: 'audio/x-wav', 
  wma: 'audio/x-ms-wma', 
  wmv: 'video/x-ms-wmv', 
  xml: 'text/xml' 
 }  
 const requestUrl = req.url  
 let pathName = url.parse(requestUrl).pathname  
 // 中文亂碼處理 
 pathName = decodeURI(pathName)  
 let ext = path.extname(pathName)  
 // 特殊 url 處理 
 if (!pathName.endsWith('/') && ext === '' && !requestUrl.includes('?')) { 
  pathName += '/' 
  const redirect = `http://${req.headers.host}${pathName}` 
  redirectUrl(redirect, res) 
 }  
 // 解釋 url 對(duì)應(yīng)的資源文件路徑 
 let filePath = path.resolve(__dirname + pathName)  
 // 設(shè)置 mime 
 ext = ext ? ext.slice(1) : 'unknown' 
 const contentType = mime[ext] || 'text/plain' 
 
 // 處理資源文件 
 fs.stat(filePath, (err, stats) => {   
  if (err) { 
   res.writeHead(404, { 'content-type': 'text/html;charset=utf-8' }) 
   res.end('<h1>404 Not Found</h1>')    
   return 
  }   
  // 處理文件 
  if (stats.isFile()) { 
   readFile(filePath, contentType, res) 
  }   
  // 處理目錄 
  if (stats.isDirectory()) {    
   let html = "<head><meta charset = 'utf-8'/></head><body><ul>" 
   // 遍歷文件目錄,以超鏈接返回,方便用戶選擇 
   fs.readdir(filePath, (err, files) => {     
    if (err) { 
     res.writeHead(500, { 'content-type': contentType }) 
     res.end('<h1>500 Server Error</h1>') 
     return 
    } else {      
     for (let file of files) {       
      if (file === 'index.html') {        
       const redirect = `http://${req.headers.host}${pathName}index.html` 
       redirectUrl(redirect, res) 
      } 
      html += `<li><a href='${file}'>${file}</a></li>` 
     } 
     html += '</ul></body>' 
     res.writeHead(200, { 'content-type': 'text/html' }) 
     res.end(html) 
    } 
   }) 
  } 
 }) 
} 
// 重定向處理 
function redirectUrl(url, res) { 
 url = encodeURI(url) 
 res.writeHead(302, { 
  location: url 
 }) 
 res.end() 
} 
// 文件讀取 
function readFile(filePath, contentType, res) { 
 res.writeHead(200, { 'content-type': contentType }) 
 const stream = fs.createReadStream(filePath) 
 stream.on('error', function() { 
  res.writeHead(500, { 'content-type': contentType }) 
  res.end('<h1>500 Server Error</h1>') 
 }) 
 stream.pipe(res) 
} 

2、代理功能

// 代理列表 
const proxyTable = { 
 '/api': { 
  target: 'http://127.0.0.1:8090/api', 
  changeOrigin: true 
 } 
} 
// 處理代理列表 
function processProxy(req, res) {  
 const requestUrl = req.url  
 const proxy = Object.keys(proxyTable)  
 let not_found = true 
 for (let index = 0; index < proxy.length; index++) {   
   const k = proxy[index]   
   const i = requestUrl.indexOf(k)   
   if (i >= 0) { 
    not_found = false 
    const element = proxyTable[k]    
    const newUrl = element.target + requestUrl.slice(i + k.length)    
    if (requestUrl !== newUrl) {    
     const u = url.parse(newUrl, true)     
     const options = { 
      hostname : u.hostname, 
      port   : u.port || 80, 
      path   : u.path,    
      method  : req.method, 
      headers : req.headers, 
      timeout : 6000 
     }     
     if(element.changeOrigin){ 
      options.headers['host'] = u.hostname + ':' + ( u.port || 80) 
     }     
     const request = http 
     .request(options, response => {       
      // cookie 處理 
      if(element.changeOrigin && response.headers['set-cookie']){ 
       response.headers['set-cookie'] = getHeaderOverride(response.headers['set-cookie']) 
      } 
      res.writeHead(response.statusCode, response.headers) 
      response.pipe(res) 
     }) 
     .on('error', err => {      
      res.statusCode = 503 
      res.end() 
     }) 
    req.pipe(request) 
   }    
   break 
  } 
 }  
 return not_found 
} 
function getHeaderOverride(value){  
 if (Array.isArray(value)) {    
  for (var i = 0; i < value.length; i++ ) { 
   value[i] = replaceDomain(value[i]) 
  } 
 } else { 
  value = replaceDomain(value) 
 }  
 return value 
} 
function replaceDomain(value) {  
 return value.replace(/domain=[a-z.]*;/,'domain=.localhost;').replace(/secure/, '') 
} 

3、完整版

服務(wù)器接收到 http 請(qǐng)求,首先處理代理列表 proxyTable,然后再處理靜態(tài)資源。雖然這里面只有二個(gè)步驟,但如果按照先后順序編碼,這種方式顯然不夠靈活,不利于以后功能的擴(kuò)展。koa 框架的中間件就是一個(gè)很好的解決方案。完整代碼如下:

'use strict' 
 
const http = require('http') 
const url = require('url') 
const fs = require('fs') 
const path = require('path') 
const cp = require('child_process') 
// 處理靜態(tài)資源 
function processStatic(req, res) {  
 const mime = { 
  css: 'text/css', 
  gif: 'image/gif', 
  html: 'text/html', 
  ico: 'image/x-icon', 
  jpeg: 'image/jpeg', 
  jpg: 'image/jpeg', 
  js: 'text/javascript', 
  json: 'application/json', 
  pdf: 'application/pdf', 
  png: 'image/png', 
  svg: 'image/svg+xml', 
  woff: 'application/x-font-woff', 
  woff2: 'application/x-font-woff', 
  swf: 'application/x-shockwave-flash', 
  tiff: 'image/tiff', 
  txt: 'text/plain', 
  wav: 'audio/x-wav', 
  wma: 'audio/x-ms-wma', 
  wmv: 'video/x-ms-wmv', 
  xml: 'text/xml' 
 }  
 const requestUrl = req.url  
 let pathName = url.parse(requestUrl).pathname  
 // 中文亂碼處理 
 pathName = decodeURI(pathName)  
 let ext = path.extname(pathName)  
 // 特殊 url 處理 
 if (!pathName.endsWith('/') && ext === '' && !requestUrl.includes('?')) { 
  pathName += '/' 
  const redirect = `http://${req.headers.host}${pathName}` 
  redirectUrl(redirect, res) 
 }  
 // 解釋 url 對(duì)應(yīng)的資源文件路徑 
 let filePath = path.resolve(__dirname + pathName)  
 // 設(shè)置 mime 
 ext = ext ? ext.slice(1) : 'unknown' 
 const contentType = mime[ext] || 'text/plain' 
 
 // 處理資源文件 
 fs.stat(filePath, (err, stats) => {   
  if (err) { 
   res.writeHead(404, { 'content-type': 'text/html;charset=utf-8' }) 
   res.end('<h1>404 Not Found</h1>')    
   return 
  }  // 處理文件 
  if (stats.isFile()) { 
   readFile(filePath, contentType, res) 
  }  // 處理目錄 
  if (stats.isDirectory()) {    
   let html = "<head><meta charset = 'utf-8'/></head><body><ul>" 
   // 遍歷文件目錄,以超鏈接返回,方便用戶選擇 
   fs.readdir(filePath, (err, files) => {     
    if (err) { 
     res.writeHead(500, { 'content-type': contentType }) 
     res.end('<h1>500 Server Error</h1>') 
     return 
    } else {     
      for (let file of files) {       
      if (file === 'index.html') {       
       const redirect = `http://${req.headers.host}${pathName}index.html` 
       redirectUrl(redirect, res) 
      } 
      html += `<li><a href='${file}'>${file}</a></li>` 
     } 
     html += '</ul></body>' 
     res.writeHead(200, { 'content-type': 'text/html' }) 
     res.end(html) 
    } 
   }) 
  } 
 }) 
} 
// 重定向處理 
function redirectUrl(url, res) { 
 url = encodeURI(url) 
 res.writeHead(302, { 
  location: url 
 }) 
 res.end() 
} 
// 文件讀取 
function readFile(filePath, contentType, res) { 
 res.writeHead(200, { 'content-type': contentType }) 
 const stream = fs.createReadStream(filePath) 
 stream.on('error', function() { 
  res.writeHead(500, { 'content-type': contentType }) 
  res.end('<h1>500 Server Error</h1>') 
 }) 
 stream.pipe(res) 
} 
// 處理代理列表 
function processProxy(req, res) { 
 const requestUrl = req.url 
 const proxy = Object.keys(proxyTable) 
 let not_found = true 
 for (let index = 0; index < proxy.length; index++) {   
  const k = proxy[index]   
  const i = requestUrl.indexOf(k)   
  if (i >= 0) { 
   not_found = false 
   const element = proxyTable[k] 
   const newUrl = element.target + requestUrl.slice(i + k.length) 
 
   if (requestUrl !== newUrl) { 
    const u = url.parse(newUrl, true) 
    const options = { 
     hostname : u.hostname, 
     port   : u.port || 80, 
     path   : u.path,    
     method  : req.method, 
     headers : req.headers, 
     timeout : 6000 
    }; 
    if(element.changeOrigin){ 
     options.headers['host'] = u.hostname + ':' + ( u.port || 80) 
    } 
    const request = 
     http.request(options, response => {         
      // cookie 處理 
      if(element.changeOrigin && response.headers['set-cookie']){ 
       response.headers['set-cookie'] = getHeaderOverride(response.headers['set-cookie']) 
      } 
      res.writeHead(response.statusCode, response.headers) 
      response.pipe(res) 
     }) 
     .on('error', err => { 
      res.statusCode = 503 
      res.end() 
     }) 
    req.pipe(request) 
   } 
   break 
  } 
 } 
 return not_found 
} 
function getHeaderOverride(value){ 
 if (Array.isArray(value)) { 
   for (var i = 0; i < value.length; i++ ) {     
     value[i] = replaceDomain(value[i]) 
   } 
 } else { 
   value = replaceDomain(value) 
 } 
 return value} 
function replaceDomain(value) { 
 return value.replace(/domain=[a-z.]*;/,'domain=.localhost;').replace(/secure/, '') 
} 
function compose (middleware) { 
 if (!Array.isArray(middleware)) throw new TypeError('Middleware stack must be an array!')  
 for (const fn of middleware) {   
  if (typeof fn !== 'function') throw new TypeError('Middleware must be composed of functions!') 
 }  
 return function (context, next) { 
  // 記錄上一次執(zhí)行中間件的位置   
  let index = -1 
  return dispatch(0)  
  function dispatch (i) { 
   // 理論上 i 會(huì)大于 index,因?yàn)槊看螆?zhí)行一次都會(huì)把 i遞增, 
   // 如果相等或者小于,則說明next()執(zhí)行了多次   
   if (i <= index) return Promise.reject(new Error('next() called multiple times'))    
   index = i 
   let fn = middleware[i]    
   if (i === middleware.length) fn = next 
   if (!fn) return Promise.resolve()   
   try {    
    return Promise.resolve(fn(context, function next () {  
      return dispatch(i + 1) 
    })) 
   } catch (err) {     
     return Promise.reject(err) 
   } 
  } 
 } 
} 
function Router(){  
 this.middleware = [] 
} 
Router.prototype.use = function (fn){  
 if (typeof fn !== 'function') throw new TypeError('middleware must be a function!') 
 this.middleware.push(fn) 
 return this} 
Router.prototype.callback= function() {  
 const fn = compose(this.middleware)  
 const handleRequest = (req, res) => { 
  const ctx = {req, res} 
  return this.handleRequest(ctx, fn) 
 } 
 return handleRequest 
} 
Router.prototype.handleRequest= function(ctx, fn) { 
 fn(ctx) 
} 
 
// 代理列表 
const proxyTable = { 
 '/api': { 
  target: 'http://127.0.0.1:8090/api', 
  changeOrigin: true 
 } 
} 
 
const port = 8080 
const hostname = 'localhost' 
const appRouter = new Router() 
 
// 使用中間件 
appRouter.use(async(ctx,next)=>{ 
 if(processProxy(ctx.req, ctx.res)){ 
  next() 
 } 
}).use(async(ctx)=>{ 
 processStatic(ctx.req, ctx.res) 
}) 
 
// 創(chuàng)建 http 服務(wù) 
let httpServer = http.createServer(appRouter.callback()) 
 
// 設(shè)置監(jiān)聽端口 
httpServer.listen(port, hostname, () => { 
 console.log(`app is running at port:${port}`) 
 console.log(`url: http://${hostname}:${port}`) 
 cp.exec(`explorer http://${hostname}:${port}`, () => {}) 
}) 

以上就是本文的全部內(nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • npm的lock機(jī)制解析

    npm的lock機(jī)制解析

    這篇文章主要介紹了npm的lock機(jī)制解析,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2019-06-06
  • 手把手帶你搭建一個(gè)node cli的方法示例

    手把手帶你搭建一個(gè)node cli的方法示例

    這篇文章主要介紹了手把手帶你搭建一個(gè)node cli的方法示例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-08-08
  • node.js正則表達(dá)式獲取網(wǎng)頁中所有鏈接的代碼實(shí)例

    node.js正則表達(dá)式獲取網(wǎng)頁中所有鏈接的代碼實(shí)例

    這篇文章主要介紹了node.js正則表達(dá)式獲取網(wǎng)頁中所有鏈接的代碼實(shí)例,使用正則表達(dá)式實(shí)現(xiàn),需要的朋友可以參考下
    2014-06-06
  • Node.js+Express+MySql實(shí)現(xiàn)用戶登錄注冊(cè)功能

    Node.js+Express+MySql實(shí)現(xiàn)用戶登錄注冊(cè)功能

    這篇文章主要為大家詳細(xì)介紹了Node.js+Express+MySql實(shí)現(xiàn)用戶登錄注冊(cè),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-07-07
  • 在Express中提供靜態(tài)文件的實(shí)現(xiàn)方法

    在Express中提供靜態(tài)文件的實(shí)現(xiàn)方法

    這篇文章主要介紹了在Express中提供靜態(tài)文件的實(shí)現(xiàn)方法,將包含靜態(tài)資源的目錄的名稱傳遞給 express.static 中間件函數(shù),以便開始直接提供這些文件,感興趣的可以了解一下
    2019-10-10
  • ubuntu編譯nodejs所需的軟件并安裝

    ubuntu編譯nodejs所需的軟件并安裝

    Node 在 Linux,Macintosh,Solaris 這幾個(gè)系統(tǒng)上都可以完美的運(yùn)行,linux 的發(fā)行版本當(dāng)中使用 Ubuntu 相當(dāng)適合。這也是我們?yōu)槭裁匆獓L試在 ubuntu 上安裝 Node.js,
    2017-09-09
  • 基于node.js之調(diào)試器詳解

    基于node.js之調(diào)試器詳解

    下面小編就為大家?guī)硪黄趎ode.js之調(diào)試器詳解。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-08-08
  • nodejs版本管理工具nvm的安裝與使用小結(jié)

    nodejs版本管理工具nvm的安裝與使用小結(jié)

    在項(xiàng)目開發(fā)過程中,使用到vue框架技術(shù),需要安裝node下載項(xiàng)目依賴,本文主要介紹了nodejs版本管理工具nvm的安裝與使用小結(jié),具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-01-01
  • 解決await在forEach中不起作用的問題

    解決await在forEach中不起作用的問題

    這篇文章主要介紹了解決await在forEach中不起作用的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2021-02-02
  • 快速了解Node中的Stream流是什么

    快速了解Node中的Stream流是什么

    今天小編就為大家分享一篇關(guān)于快速了解Node中的Stream流是什么,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧
    2019-02-02

最新評(píng)論

上思县| 信丰县| 克山县| 禹城市| 亚东县| 吉林市| 隆子县| 永胜县| 广东省| 张家港市| 莆田市| 建德市| 同心县| 巩留县| 攀枝花市| 滦南县| 布尔津县| 绥化市| 贵州省| 象山县| 方山县| 武夷山市| 光山县| 镇康县| 广昌县| 望谟县| 仙桃市| 囊谦县| 游戏| 贵阳市| 攀枝花市| 凤山县| 华宁县| 随州市| 大足县| 松潘县| 固阳县| 聂拉木县| 苏州市| 察哈| 司法|