使用nodejs、Python写的一个简易HTTP静态文件服务器


Posted in NodeJs onJuly 18, 2014

日常开发过程中,我们经常需要修改一些放在 CDN 上的静态文件(如 JavaScript、CSS、HTML 文件等),这个过程中,我们希望能有一种方式将线上 CDN 的目录映射为本地硬盘上的某个目录,这样,当我们在本地修改了某个文件时,不需要发布,刷新后马上能看到效果。

比如,我们的 CDN 域名是:http://a.mycdn.com,本地对应的目录是:D:\workassets,我们希望所有对 http://a.mycdn.com/* 的访问被映射到本地的 D:\workassets\* 下。如访问 http://a.mycdn.com/s/atp.js 时,实际上是读取的是本地的 D:\workassetss\atp.js,而不需要从网上下载线上的文件。

实现这个功能很简单,关键点如下:

1、在本地开启一个 HTTP 服务,监听 80 端口;
2、修改系统 hosts 文件,添加“127.0.0.1 a.mycdn.com”,将 CDN 域名绑定为本地服务器地址;
3、配置本地 HTTP 服务,接收到一个 GET 请求后,先检查本地硬盘上是否存在对应的文件,如存在,则返回这个文件的内容,如不存在,则返回线上对应的内容。

可以看到,关键部分是需要搭建一个本地的 HTTP 服务。这方面有很多教程,比如在本地安装 Apache 或 Ngnix 等服务器软件,再配置相应的转发规则等。不过个人觉得这类方法还是有点复杂,本文要介绍的,是另外的不需要安装服务器软件的方法。

因为我们是在本地开发调试,对性能、并发性的要求并不高,因此我们其实并不需要一个像 Apache/Ngnix 这样的专业的 HTTP 软件,我们只需要一段能提供 HTTP 服务的脚本即可。比如用 nodejs 来实现。

/**

 * author: oldj

 *

 **/
var http = require("http"),

 url = require("url"),

 path = require("path"),

 fs = require("fs"),

 local_folders,

 base_url;
local_folders = [ // 本地路径,代理将在这个列表中的目录下寻找文件,如果没有找到则转到线上地址

 "D:/work/assets"

];

base_url = "http://10.232.133.214"; // 线上路径,如果找不到文件,则转向到这个地址


function loadFile(pathname, response) {

 var i, l = local_folders.length,

  fn;
 console.log("try to load " + pathname);
 for (i = 0; i < l; i++) {
  fn = local_folders[i] + pathname;

  if (path.existsSync(fn) && fs.statSync(fn).isFile()) {

   fs.readFile(fn, function (err, data) {

    response.writeHead(200);

    response.write(data);

    response.end();

   });
   return;

  }
 }
 response.writeHead(302, {

  "Location":base_url + pathname

 });

 response.end();

}
http.createServer(

 function (request, response) {
  var req_url = request.url,

   pathname;
  // 处理类似 http://a.tbcdn.cn/??p/global/1.0/global-min.css,tbsp/tbsp.css?t=20110920172000.css 的请求

  pathname = req_url.indexOf("??") == -1 ? url.parse(request.url).pathname : req_url;

  console.log("Request for '" + pathname + "' received.");

  loadFile(pathname, response);
 }).listen(80);

注意将上面的 local_folders 和 base_url 两个变量的值修改为你需要的值。将这个文件保存下来,比如保存为 local-cdn-proxy.js,然后在命令行里执行“node local-cdn-proxy.js”,本地服务器就运行起来了,当然,别忘了绑定 hosts 。

当通过 http 访问一个路径时,上面的脚本会先在本地对应的目录下查找,找到则返回对应文件的内容,找不到则直接 302 跳转到线上对应的地址。对于找不到的情况,还有一种处理办法是由本地服务器从线上下载对应的内容并返回,不过对这个需求来说,302 跳转就足够了。

除了 nodejs 版本,我也写了一个 Python 的版本:

# -*- coding: utf-8 -*-

#

# author: oldj

#
import os

import BaseHTTPServer
LOCAL_FOLDERS = [

    "D:/work/assets"

]

BASE_URL = "http://10.232.133.214"
class WebRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
    def do_GET(self):

        print "Request for '%s' received." % self.path

        for folder in LOCAL_FOLDERS:

            fn = os.path.join(folder, self.path.replace("/", os.sep)[1:])

            if os.path.isfile(fn):

                self.send_response(200)

                self.wfile.write(open(fn, "rb").read())

                break
        else:

            self.send_response(302)

            self.send_header("Location", "%s%s" % (BASE_URL, self.path))
server = BaseHTTPServer.HTTPServer(("0.0.0.0", 80), WebRequestHandler)

server.serve_forever()

可以看到,Python 版本的代码比 nodejs 版本的精简了很多。

上面的两段代码的功能还相对比较简单,比如没有输出内容的 MIME-Type、Content-Length 等头信息,对可能的阻塞操作(如读取文件超时等)也没有做特别的处理。对于本地开发环境来说,它们已经是可以工作的版本了,你也可以继续扩展这两个脚本,以便满足更多的需求。

NodeJs 相关文章推荐
nodejs教程之入门
Nov 21 NodeJs
用nodejs搭建websocket服务器
Jan 23 NodeJs
nodejs搭建本地服务器并访问文件的方法
Mar 03 NodeJs
NodeJs测试框架Mocha的安装与使用
Mar 28 NodeJs
详解如何在NodeJS项目中优雅的使用ES6
Apr 22 NodeJs
nodejs 图片预览和上传的示例代码
Sep 30 NodeJs
windows系统下更新nodejs版本的方案
Nov 24 NodeJs
nodejs基于WS模块实现WebSocket聊天功能的方法
Jan 12 NodeJs
使用npm安装最新版本nodejs
Jan 18 NodeJs
Nodejs 和 Electron ubuntu下快速安装过程
May 04 NodeJs
NodeJS加密解密及node-rsa加密解密用法详解
Oct 12 NodeJs
Nodejs实现的操作MongoDB数据库功能完整示例
Feb 02 NodeJs
抛弃Nginx使用nodejs做反向代理服务器
Jul 17 #NodeJs
nodejs的10个性能优化技巧
Jul 15 #NodeJs
提高NodeJS中SSL服务的性能
Jul 15 #NodeJs
在NodeJS中启用ECMAScript 6小结(windos以及Linux)
Jul 15 #NodeJs
nodejs 实现模拟form表单上传文件
Jul 14 #NodeJs
14款NodeJS Web框架推荐
Jul 11 #NodeJs
基于promise.js实现nodejs的promises库
Jul 06 #NodeJs
You might like
探讨捕获php错误信息方法的详解
2013/06/09 PHP
PHP获取当前日期所在星期(月份)的开始日期与结束日期(实现代码)
2013/06/18 PHP
Zend Framework缓存Cache用法简单实例
2016/03/19 PHP
如何使用php等比例缩放图片
2016/10/12 PHP
ThinkPHP类似AOP思想的参数验证的实现方法
2019/12/18 PHP
javascript 火狐(firefox)不显示本地图片问题解决
2008/07/05 Javascript
33种Javascript 表格排序控件收集
2009/12/03 Javascript
网络之美 JavaScript中Get和Set访问器的实现代码
2010/09/19 Javascript
iframe跨域通信封装详解
2015/08/11 Javascript
javascript事件捕获机制【深入分析IE和DOM中的事件模型】
2016/12/15 Javascript
jQuery is not defined 错误原因与解决方法小结
2017/03/19 Javascript
angularjs指令之绑定策略(@、=、&amp;)
2017/04/13 Javascript
Angular.JS通过指令操作DOM的方法
2017/05/10 Javascript
js经验分享 JavaScript反调试技巧
2018/03/10 Javascript
AngularJS下$http服务Post方法传递json参数的实例
2018/03/29 Javascript
vue写一个组件
2018/04/09 Javascript
jQuery中实现text()的方法
2019/04/04 jQuery
vuejs element table 表格添加行,修改,单独删除行,批量删除行操作
2020/07/18 Javascript
python实现web方式logview的方法
2015/08/10 Python
Python处理PDF及生成多层PDF实例代码
2017/04/24 Python
Tensorflow实现AlexNet卷积神经网络及运算时间评测
2018/05/24 Python
用PyInstaller把Python代码打包成单个独立的exe可执行文件
2018/05/26 Python
Python合并同一个文件夹下所有PDF文件的方法
2019/03/11 Python
Python requests模块session代码实例
2020/04/14 Python
python中类与对象之间的关系详解
2020/12/16 Python
索引覆盖(Index Covering)查询含义
2012/02/18 面试题
会计实习生工作总结的自我评价
2013/10/07 职场文书
项目计划书范文
2014/01/09 职场文书
新年联欢会主持词
2014/03/27 职场文书
文明社区申报材料
2014/08/21 职场文书
三严三实对照检查材料思想汇报
2014/09/28 职场文书
大学生翘课检讨书范文
2014/10/06 职场文书
学雷锋倡议书
2015/01/19 职场文书
行政上诉状范文
2015/05/23 职场文书
标准演讲稿格式结尾应该怎么书写?
2019/07/17 职场文书
如何使JavaScript休眠或等待
2021/04/27 Javascript