热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Node.js原生api搭建web服务器的方法步骤

这篇文章主要介绍了Node.js原生api搭建web服务器的方法步骤,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

node.js 实现一个简单的 web 服务器还是比较简单的,以前利用 express 框架实现过『nodeJS搭一个简单的(代理)web服务器』。代码量很少,可是使用时需要安装依赖,多处使用难免有点不方便。于是便有了完全使用原生 api 来重写的想法,也当作一次 node.js 复习。

1、静态 web 服务器

'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' 
 
// 创建 http 服务 
let httpServer = http.createServer(processStatic) 
// 设置监听端口 
httpServer.listen(port, hostname, () => {  
 console.log(`app is running at port:${port}`)  
 console.log(`url: http://${hostname}:${port}`) 
 cp.exec(`explorer http://${hostname}:${port}`, () => {}) 
}) 
// 处理静态资源 
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 对应的资源文件路径 
 let filePath = path.resolve(__dirname + pathName)  
 // 设置 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('

404 Not Found

') return } // 处理文件 if (stats.isFile()) { readFile(filePath, contentType, res) } // 处理目录 if (stats.isDirectory()) { let html = "
    " // 遍历文件目录,以超链接返回,方便用户选择 fs.readdir(filePath, (err, files) => { if (err) { res.writeHead(500, { 'content-type': contentType }) res.end('

    500 Server Error

    ') return } else { for (let file of files) { if (file === 'index.html') { const redirect = `http://${req.headers.host}${pathName}index.html` redirectUrl(redirect, res) } html += `
  • ${file}
  • ` } html += '
' 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('

500 Server Error

') }) 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 = 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 

3、完整版

服务器接收到 http 请求,首先处理代理列表 proxyTable,然后再处理静态资源。虽然这里面只有二个步骤,但如果按照先后顺序编码,这种方式显然不够灵活,不利于以后功能的扩展。koa 框架的中间件就是一个很好的解决方案。完整代码如下:

'use strict' 
 
const http = require('http') 
const url = require('url') 
const fs = require('fs') 
const path = require('path') 
const cp = require('child_process') 
// 处理静态资源 
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 对应的资源文件路径 
 let filePath = path.resolve(__dirname + pathName)  
 // 设置 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('

404 Not Found

') return } // 处理文件 if (stats.isFile()) { readFile(filePath, contentType, res) } // 处理目录 if (stats.isDirectory()) { let html = "
    " // 遍历文件目录,以超链接返回,方便用户选择 fs.readdir(filePath, (err, files) => { if (err) { res.writeHead(500, { 'content-type': contentType }) res.end('

    500 Server Error

    ') return } else { for (let file of files) { if (file === 'index.html') { const redirect = `http://${req.headers.host}${pathName}index.html` redirectUrl(redirect, res) } html += `
  • ${file}
  • ` } html += '
' 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('

500 Server Error

') }) 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 = 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 { 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) }) // 创建 http 服务 let httpServer = http.createServer(appRouter.callback()) // 设置监听端口 httpServer.listen(port, hostname, () => { console.log(`app is running at port:${port}`) console.log(`url: http://${hostname}:${port}`) cp.exec(`explorer http://${hostname}:${port}`, () => {}) })

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。


推荐阅读
  • 用JavaScript实现的太空人手表
    用JavaScript实现的太空人手表-JS写的太空人手表,没有用canvas、svg。主要用几个大的函数来动态显示时间、天气这些。天气的获取用到了AJAX请求。代码中有详细的注释 ... [详细]
  • VScode格式化文档换行或不换行的设置方法
    本文介绍了在VScode中设置格式化文档换行或不换行的方法,包括使用插件和修改settings.json文件的内容。详细步骤为:找到settings.json文件,将其中的代码替换为指定的代码。 ... [详细]
  • 本文介绍了在开发Android新闻App时,搭建本地服务器的步骤。通过使用XAMPP软件,可以一键式搭建起开发环境,包括Apache、MySQL、PHP、PERL。在本地服务器上新建数据库和表,并设置相应的属性。最后,给出了创建new表的SQL语句。这个教程适合初学者参考。 ... [详细]
  • Java验证码——kaptcha的使用配置及样式
    本文介绍了如何使用kaptcha库来实现Java验证码的配置和样式设置,包括pom.xml的依赖配置和web.xml中servlet的配置。 ... [详细]
  • iOS超签签名服务器搭建及其优劣势
    本文介绍了搭建iOS超签签名服务器的原因和优势,包括不掉签、用户可以直接安装不需要信任、体验好等。同时也提到了超签的劣势,即一个证书只能安装100个,成本较高。文章还详细介绍了超签的实现原理,包括用户请求服务器安装mobileconfig文件、服务器调用苹果接口添加udid等步骤。最后,还提到了生成mobileconfig文件和导出AppleWorldwideDeveloperRelationsCertificationAuthority证书的方法。 ... [详细]
  • Node.js学习笔记(一)package.json及cnpm
    本文介绍了Node.js中包的概念,以及如何使用包来统一管理具有相互依赖关系的模块。同时还介绍了NPM(Node Package Manager)的基本介绍和使用方法,以及如何通过NPM下载第三方模块。 ... [详细]
  • RN即ReactNative基于React框架针对移动端的跨平台框架,在学习RN前建议最好熟悉下html,css,js,当然如果比较急,那就直接上手吧,毕竟用学习前面基础的时间,R ... [详细]
  • 表单提交前的最后验证:通常在表单提交前,我们必须确认用户是否都把必须填选的做了,如果没有,就不能被提交到服务器,这里我们用到表单的formname.submit()看演示,其实这个对于我们修炼道 ... [详细]
  • Itwasworkingcorrectly,butyesterdayitstartedgiving401.IhavetriedwithGooglecontactsAPI ... [详细]
  • ①安装node.js②按照下面命令行执行node安装参照网址:https:www.cnblogs.compearl07p6247389.htmlwebpack讲解安 ... [详细]
  • 这是原文链接:sendingformdata许多情况下,我们使用表单发送数据到服务器。服务器处理数据并返回响应给用户。这看起来很简单,但是 ... [详细]
  • 本文介绍了使用AJAX的POST请求实现数据修改功能的方法。通过ajax-post技术,可以实现在输入某个id后,通过ajax技术调用post.jsp修改具有该id记录的姓名的值。文章还提到了AJAX的概念和作用,以及使用async参数和open()方法的注意事项。同时强调了不推荐使用async=false的情况,并解释了JavaScript等待服务器响应的机制。 ... [详细]
  • 本文讨论了Alink回归预测的不完善问题,指出目前主要针对Python做案例,对其他语言支持不足。同时介绍了pom.xml文件的基本结构和使用方法,以及Maven的相关知识。最后,对Alink回归预测的未来发展提出了期待。 ... [详细]
  • 禁止程序接收鼠标事件的工具_VNC Viewer for Mac(远程桌面工具)免费版
    VNCViewerforMac是一款运行在Mac平台上的远程桌面工具,vncviewermac版可以帮助您使用Mac的键盘和鼠标来控制远程计算机,操作简 ... [详细]
  • CentOS 7部署KVM虚拟化环境之一架构介绍
    本文介绍了CentOS 7部署KVM虚拟化环境的架构,详细解释了虚拟化技术的概念和原理,包括全虚拟化和半虚拟化。同时介绍了虚拟机的概念和虚拟化软件的作用。 ... [详细]
author-avatar
米米清澈_109
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有