从零开始学习Node.js系列教程之设置HTTP头的方法示例


Posted in Javascript onApril 13, 2017

本文实例讲述了Node.js设置HTTP头的方法。分享给大家供大家参考,具体如下:

server.js

//basic server的配置文件
var port = 3000;
var server = require('./basicserver').createServer();
server.useFavIcon("localhost", "./docroot/favicon.png");
server.addContainer(".*", "/l/(.*)$", require('./redirector'), {})
server.docroot("localhost", "/", "./docroot");
//server.useFavIcon("127.0.0.1", "./docroot/favicon.png");
//server.docroot("127.0.0.1", "/", "./docroot");
server.listen(port);

basicserver.js

Response Header 服务器发送到客户端

文件扩展名不足以完全恰当的标识文件类型,而且文件扩展名没有标准,于是,人们设计了Content-Type头和整个MIME类型标准来作为数据类型的表示系统。

对于某些应用,特别是一些处理固定数据的小型应用,我们可以精准的知道该使用哪一种Content-Type头,因为应用发送的数据是特定已知的。然而staticHandler能发送任何文件,通常不知道该使用哪种Content-Type。通过匹配文件扩展名列表和Content-Type可以解决这个问题,但是这个方案不完美。最好的实践方案是使用一个外部的配置文件,它通常由操作系统提供。

MIME npm包使用了Apache项目的mime.types文件,该文件包含超过600个Content-Type的有关数据,如果有需要,mime模块也支持添加自定义的MIME类型。

npm install mime

var mime = require('mime');
var mimeType = mime.lookup('image.gif'); //==> image/gif
res.setHeader('Content-Type', mimeType);

一些相关的HTTP头:

Content-Encoding 数据被编码时使用,例如gzip
Content-Language 内容中使用的语言
Content-Length 字节数
Content-Location 能取到数据的一个候补位置
Content-MD5 内容主题的MD5校验和

HTTP协议是无状态的,意味着web服务器不能辨认不同的请求发送端。现在普遍的做法是,服务器发送cookie到客户端浏览器,cookie中定义了登陆用户的身份,对于每一次请求,web浏览器都会发送对应所访问网站的cookie。

发送cookie时,我们应以如下方式为Set-Cookie或Set-Cookie2头设一个值:

res.setHeader('Set-Cookie2', ..cookie value..);
/*
 Basic Server的核心模块会创建一个HTTP服务器对象,附加Basic Server上用于检查请求,然后给予适当响应的功能
 Basic Server可以通过判断Host头部匹配的容器对象响应来自多个域名的请求
 */
var http = require('http');
var url = require('url');
exports.createServer = function(){
  var htserver = http.createServer(function(req, res){
    req.basicServer = {urlparsed: url.parse(req.url, true)};
    processHeaders(req, res);
    dispatchToContainer(htserver, req, res);
  });
  htserver.basicServer = {containers: []};
  htserver.addContainer = function(host, path, module, options){
    if (lookupContainer(htserver, host, path) != undefined){
      throw new Error("Already mapped " + host + "/" + path);
    }
    htserver.basicServer.containers.push({host: host, path: path, module: module, options: options});
    return this;
  }
  htserver.useFavIcon = function(host, path){
    return this.addContainer(host, "/favicon.ico", require('./faviconHandler'), {iconPath: path});
  }
  htserver.docroot = function(host, path, rootPath){
    return this.addContainer(host, path, require('./staticHandler'), {docroot: rootPath});
  }
  return htserver;
}
var lookupContainer = function(htserver, host, path){
  for (var i = 0; i < htserver.basicServer.containers.length; i++){
    var container = htserver.basicServer.containers[i];
    var hostMatches = host.toLowerCase().match(container.host);
    var pathMatches = path.match(container.path);
    if (hostMatches !== null && pathMatches !== null){
      return {container: container, host: hostMatches, path: pathMatches};
    }
  }
  return undefined;
}
//用于搜索req.headers数组以查找cookie和host头部,因为这两个字段对请求的分派都很重要
//这个函数在每一个HTTP请求到达时都会被调用
//还有很多其他的HTTP头部字段(Accept Accept-Encoding Accept-Language User-Agent)
var processHeaders = function(req, res){
  req.basicServer.cookies = [];
  var keys = Object.keys(req.headers);
  for (var i = 0; i < keys.length; i++){
    var hname = keys[i];
    var hval = req.headers[hname];
    if (hname.toLowerCase() === "host"){
      req.basicServer.host = hval;
    }
    //提取浏览器发送的cookie
    if (hname.toLowerCase() === "cookie"){
      req.basicServer.cookies.push(hval);
    }
  }
}
//查找匹配的容器,分派请求到对应的容器中
//这个函数在每一个HTTP请求到达时都会被调用
var dispatchToContainer = function(htserver, req, res){
  var container = lookupContainer(htserver, req.basicServer.host, req.basicServer.urlparsed.pathname);
  if (container !== undefined){
    req.basicServer.hostMatches = container.host;
    req.basicServer.pathMatches = container.path;
    req.basicServer.container = container.container;
    container.container.module.handle(req, res);
  }else {
    res.writeHead(404, {'Content-Type': 'text/plain'});
    res.end("no handler found for " + req.basicServer.host + "/" + req.basicServer.urlparsed);
  }
}

staticHandler.js

//用于处理文件系统内的文件,docroot选项指被存放文件所在文件夹的路径,读取该目录下的指定文件
var fs = require('fs');
var mime = require('mime');
var sys = require('sys');
exports.handle = function(req, res){
  if (req.method !== "GET"){
    res.writeHead(404, {'Content-Type': 'text/plain'});
    res.end("invalid method " + req.method);
  } else {
    var fname = req.basicServer.container.options.docroot + req.basicServer.urlparsed.pathname;
    if (fname.match(/\/$/)) fname += "index.html"; //如果URL以/结尾
    fs.stat(fname, function(err, stats){
      if (err){
        res.writeHead(500, {'Content-Type': 'text/plain'});
        res.end("file " + fname + " not found " + err);
      } else {
        fs.readFile(fname, function(err, buf){
          if (err){
            res.writeHead(500, {'Content-Type': 'text/plain'});
            res.end("file " + fname + " not readable " + err);
          } else {
            res.writeHead(200, {'Content-Type': mime.lookup(fname),
              'Content-Length': buf.length});
            res.end(buf);
          }
        });
      }
    });
  }
}

faviconHandler.js

//这个处理函数处理对favicon.ico的请求
//MIME模块根据给出的图标文件确定正确的MIME类型,网站图标favicon可以是任何类型的图片,但是我们必须要告诉浏览器是哪个类型
//MIME模块,用于生成正确的Content-Type头
var fs = require('fs');
var mime = require('mime');
exports.handle = function(req, res){
  if (req.method !== "GET"){
    res.writeHead(404, {'Content-Type': 'text/plain'});
    res.end("invalid method " + req.method);
  } else if (req.basicServer.container.options.iconPath !== undefined){
    fs.readFile(req.basicServer.container.options.iconPath, function(err, buf){
      if (err){
        res.writeHead(500, {'Content-Type': 'text/plain'});
        res.end(req.basicServer.container.options.iconPath + "not found");
      } else {
        res.writeHead(200, {'Content-Type': mime.lookup(req.basicServer.container.options.iconPath),
        'Content-Length': buf.length});
        res.end(buf);
      }
    });
  } else {
    res.writeHead(404, {'Content-Type': 'text/plain'});
    res.end("no favicon");
  }
}

redirector.js

/*
 把一个域的请求重定向到另一个上,例如将www.example.com重定向到example.com上,或者使用简短的URL跳转到较长的URL
 实现这两种情况,我们需要在HTTP响应中发送301(永久移除)或者302(临时移除)状态码,并且指定location头信息。有了这个组合
 信号,web浏览器就知道要跳转到另一个web位置了
 */
//地址http://localhost:3000/l/ex1 会跳转到http://example1.com
var util = require('util');
var code2url = {'ex1': 'http://example1.com', 'ex2': "http://example2.com"};
var notFound = function(req, res){
  res.writeHead(404, {'Content-Type': 'text/plain'});
  res.end("no matching redirect code found for " + req.basicServer.host + "/" + req.basicServer.urlparsed.pathname);
}
exports.handle = function(req, res){
  if (req.basicServer.pathMatches[1]){
    var code = req.basicServer.pathMatches[1];
    if (code2url[code]){
      var url = code2url[code];
      res.writeHead(302, {'Location': url});
      res.end();
    } else {
      notFound(req, res);
    }
  } else {
    notFound(req, res);
  }
}

docroot目录下:有favicon.png

index.html

<html>
<head>
</head>
<body>
  <h1>Index</h1>
  <p>this is a index html.</p>
</body>
</html>

从零开始学习Node.js系列教程之设置HTTP头的方法示例

希望本文所述对大家nodejs程序设计有所帮助。

Javascript 相关文章推荐
JavaScript 数组运用实现代码
Apr 13 Javascript
javascript禁用键盘功能键让右击及其他键无效
Oct 09 Javascript
javaScript如何生成xmlhttp
Dec 16 Javascript
Javascript中的String对象详谈
Mar 03 Javascript
JS加载iFrame出现空白问题的解决办法
May 13 Javascript
Angular.js跨controller实现参数传递的两种方法
Feb 20 Javascript
基于jquery实现二级联动效果
Mar 30 jQuery
深入理解Node中的buffer模块
Jun 03 Javascript
jquery实现左右轮播图效果
Sep 28 jQuery
layui结合form,table的全选、反选v1.0示例讲解
Aug 15 Javascript
js+css3实现炫酷时钟
Aug 18 Javascript
详细谈谈JavaScript中循环之间的差异
Aug 23 Javascript
从零开始学习Node.js系列教程之SQLite3和MongoDB用法分析
Apr 13 #Javascript
JS 插件dropload下拉刷新、上拉加载使用小结
Apr 13 #Javascript
angularjs指令之绑定策略(@、=、&amp;)
Apr 13 #Javascript
从零开始学习Node.js系列教程六:EventEmitter发送和接收事件的方法示例
Apr 13 #Javascript
详解angularJs指令的3种绑定策略
Apr 13 #Javascript
vue2实现移动端上传、预览、压缩图片解决拍照旋转问题
Apr 13 #Javascript
Vue组件tree实现树形菜单
Apr 13 #Javascript
You might like
利用static实现表格的颜色隔行显示
2006/10/09 PHP
php中调用其他系统http接口的方法说明
2014/02/28 PHP
详解PHP中instanceof关键字及instanceof关键字有什么作用
2015/11/05 PHP
js里怎么取select标签里的值并修改
2012/12/10 Javascript
jquery实现带复选框的表格行选中删除时高亮显示
2013/08/01 Javascript
js 编码转换 gb2312 和 utf8 互转的2种方法
2013/08/07 Javascript
JavaScript中的console.assert()函数介绍
2014/12/29 Javascript
jQuery中:not选择器用法实例
2014/12/30 Javascript
jQuery插件Tmpl的简单使用方法
2015/04/27 Javascript
javascript获取文档坐标和视口坐标
2015/05/26 Javascript
JavaScript中SetInterval与setTimeout的用法详解
2015/11/10 Javascript
JavaScript获取对象在页面中位置坐标的方法
2016/02/03 Javascript
快速解决jquery.touchSwipe左右滑动和垂直滚动条冲突
2016/04/15 Javascript
vue开发心得和技巧分享
2016/10/27 Javascript
详解angular2实现ng2-router 路由和嵌套路由
2017/03/24 Javascript
Angular2平滑升级到Angular4的步骤详解
2017/03/29 Javascript
详解Chart.js轻量级图表库的使用经验
2018/05/22 Javascript
微信小程序视图控件与bindtap之间的问题的解决
2019/04/08 Javascript
使用jQuery如何写一个含验证码的登录界面
2019/05/13 jQuery
Javascript Web Worker使用过程解析
2020/03/16 Javascript
[54:33]2018DOTA2亚洲邀请赛小组赛 A组加赛 Liquid vs Optic
2018/04/03 DOTA
python通过get,post方式发送http请求和接收http响应的方法
2015/05/26 Python
Python中函数参数设置及使用的学习笔记
2016/05/03 Python
Python编程实现使用线性回归预测数据
2017/12/07 Python
使用python去除图片白色像素的实例
2019/12/12 Python
Django ModelForm操作及验证方式
2020/03/30 Python
用Python 执行cmd命令
2020/12/18 Python
使用分层画布来优化HTML5渲染的教程
2015/05/08 HTML / CSS
大学生毕业的自我鉴定
2013/11/13 职场文书
装修五一活动策划案
2014/01/23 职场文书
农村党员干部承诺书
2015/05/04 职场文书
党员进社区活动总结
2015/05/07 职场文书
婚礼家长致辞
2015/07/27 职场文书
python 爬取京东指定商品评论并进行情感分析
2021/05/27 Python
关于Numpy之repeat、tile的用法总结
2021/06/02 Python
python人工智能human learn绘图可创建机器学习模型
2021/11/23 Python