• 从零开始学习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>

  • 相关阅读:
    下载字体的正确姿势
    字体基础知识与实际运用
    CSP复习与模板
    地理必修三知识点
    LaTeX公式手册(全网最全)
    动态规划求解0/1背包问题
    JavaScript对象简介(一)
    DOM文档对象模型简介
    SQLServer 的case when语句使用实现统计
    批量初始化数组和memset函数
  • 原文地址:https://www.cnblogs.com/EricaMIN1987_IT/p/3678803.html
Copyright © 2020-2023  润新知