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

本文实例讲述了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>

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

(0)

相关推荐

  • node.js中的http.createServer方法使用说明

    方法说明: 该函数用来创建一个HTTP服务器,并将 requestListener 作为 request 事件的监听函数. 语法: 复制代码 代码如下: http.createServer([requestListener]) 由于该方法属于http模块,使用前需要引入http模块(var http= require("http") ) 接收参数: requestListener   请求处理函数,自动添加到 request 事件,函数传递两个参数: req  请求对象,想知道req有

  • 从零开始学习Node.js系列教程一:http get和post用法分析

    本文实例讲述了Node.js中http get和post用法.分享给大家供大家参考,具体如下: httpserverrequestget.js /* 获取GET请求内容 由于GET请求直接被嵌入在路径中,URL是完整的请求路径,包括了?后面的部分,因此你可以手动解析后面的内容作为GET请求的参数. node.js中url模块中的parse函数提供了这个功能. */ var http = require('http'); var url = require('url'); var util = r

  • node.js中的http.get方法使用说明

    方法说明: 由于大多数请求是不包含请求体的 GET请求.Node.js为请求提供了更加简便的方法. 该方法和 Http.request()的不同在于,该方法只以 GET 方式请求,并且会自动调用 req.end()来结束请求. 语法: 复制代码 代码如下: http.get(options, callback) 由于该方法属于http模块,使用前需要引入http模块(var http= require("http") ) 接收参数: option      表示请求网站的域名或IP地址

  • node.js中的http.response.addTrailers方法使用说明

    方法说明: 该棒法用来将HTTP trailing响应头添加到消息尾部. 语法: 复制代码 代码如下: response.addTrailers(headers) 接收参数: headers          响应头信息 例子: 复制代码 代码如下: response.writeHead(200, { 'Content-Type': 'text/plain',   'Trailer': 'Content-MD5' }); response.write(fileData); response.ad

  • 从零开始学习Node.js系列教程二:文本提交与显示方法

    本文实例讲述了Node.js文本提交与显示方法.分享给大家供大家参考,具体如下: index.js var server = require("./server"); var router = require("./router"); var requestHandlers = require("./requestHandlers"); var handle = {} handle["/"] = requestHandlers

  • 从零开始学习Node.js系列教程六:EventEmitter发送和接收事件的方法示例

    本文实例讲述了Node.js EventEmitter发送和接收事件的方法.分享给大家供大家参考,具体如下: pulser.js /* EventEmitter发送和接收事件 HTTPServer和HTTPClient类,它们都继承自EventEmitter EventEmitter被定义在Node的事件(events)模块中,直接使用EventEmitter类需要先声明require('events'), 否则不必显式声明require('events'),因为Node中很多对象都无需你调用r

  • node.js中的http.request方法使用说明

    方法说明: 函数的功能室作为客户端向HTTP服务器发起请求. 语法: 复制代码 代码如下: http.get(options, callback) 由于该方法属于http模块,使用前需要引入http模块(var http= require("http") ) 接收参数: option   数组对象,包含以下参数: host:                  表示请求网站的域名或IP地址(请求的地址). 默认为'localhost'. hostname:        服务器名称,主机

  • node.js+Ajax实现获取HTTP服务器返回数据

    我们看一个HTML5页面中通过AJAX请求的方式获取HTTP服务器返回数据的代码示例.由于我们把服务器的端口指定为1337,并将从端口为80的网站中运行HTML5页面,因此这是一种跨域操作,需要在HTTP响应头部中添加Access_Control_Allow_Origin字段,并且将参数指定为允许向服务器请求数据额域名+端口号(省略端口号时允许该域名下的任何端口向服务器请求数据), 静态页面:index.html(注:一定要放在服务器环境下,如果是win7系统的话,可以开启IIS服务,并把页面考

  • 从零开始学习Node.js系列教程三:图片上传和显示方法示例

    本文实例讲述了Node.js图片上传和显示方法.分享给大家供大家参考,具体如下: index.js var server = require("./server"); var router = require("./router"); var requestHandlers = require("./requestHandlers"); var handle = {} handle["/"] = requestHandlers

  • node.js中的http.response.writeHead方法使用说明

    方法说明: 向请求的客户端发送响应头. 该函数在一个请求内最多只能调用一次,如果不调用,则会自动生成一个响应头. 语法: 复制代码 代码如下: response.writeHead(statusCode, [reasonPhrase], [headers]) 接收参数: statusCode              HTTP状态码,如200(请求成功),404(未找到)等. reasonPhrase headers                   类似关联数组的对象,表示响应头的每个属性

  • 从零开始学习Node.js系列教程四:多页面实现的数学运算示例

    本文实例讲述了Node.js多页面实现的数学运算.分享给大家供大家参考,具体如下: app-node.js var http_port = 3000; var http = require('http'); var htutil = require('./htutil'); var server = http.createServer(function(req, res){ htutil.loadParams(req, res, undefined); if (req.requrl.pathna

  • 从零开始学习Node.js系列教程之SQLite3和MongoDB用法分析

    本文实例讲述了Node.js中SQLite3和MongoDB的用法.分享给大家供大家参考,具体如下: setup.js:初始化数据库 var util = require('util'); var async = require('async'); //npm install async var notesdb = require('./nodesdb-sqlite3'); // var notesdb = require('./notesdb-mongoose'); notesdb.conne

  • 从零开始学习Node.js系列教程五:服务器监听方法示例

    本文实例讲述了Node.js服务器监听方法.分享给大家供大家参考,具体如下: httpsnifferInvoke.js var http = require('http'); var sniffer = require('./httpsniffer'); var server = http.createServer(function(req, res){ res.writeHead(200, {'Content-Type': 'text/plain'}); res.end('Hello, Wor

  • 从零开始学习Node.js系列教程四:多页面实现数学运算的client端和server端示例

    本文实例讲述了Node.js多页面实现数学运算的client端和server端.分享给大家供大家参考,具体如下: 1.server端 支持数学运算的服务器,服务器的返回结果用json对象表示. math-server.js //通过监听3000端口使其作为Math Wizard的后台程序 var math = require('../nodejsExample3/math.js'); var express = require('express'); var app = express(); a

随机推荐