使用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爬虫抓取数据之编码问题
Jul 03 NodeJs
基于html5和nodejs相结合实现websocket即使通讯
Nov 19 NodeJs
nodeJS实现简单网页爬虫功能的实例(分享)
Jun 08 NodeJs
Nodejs之http的表单提交
Jul 07 NodeJs
NodeJS使用七牛云存储上传文件的方法
Jul 24 NodeJs
Mac 安装 nodejs方法(图文详细步骤)
Oct 30 NodeJs
NodeJS爬虫实例之糗事百科
Dec 14 NodeJs
nodejs实现的简单web服务器功能示例
Mar 15 NodeJs
详解nodejs通过响应回写的方式渲染页面资源
Apr 07 NodeJs
Nodejs中获取当前函数被调用的行数及文件名详解
Dec 12 NodeJs
nodejs对项目下所有空文件夹创建gitkeep的方法
Aug 02 NodeJs
Nodejs 微信小程序消息推送的实现
Jan 20 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读写文件的方法(生成HTML)
2006/11/27 PHP
php日期转时间戳,指定日期转换成时间戳
2012/07/17 PHP
使用PHPStorm+XDebug搭建单步调试环境
2017/11/19 PHP
JS控件autocomplete 0.11演示及下载 1月5日已更新
2007/01/09 Javascript
javascript 用记忆函数快速计算递归函数
2010/03/15 Javascript
js中widow.open()方法使用详解
2013/07/30 Javascript
同域jQuery(跨)iframe操作DOM(实例讲解)
2013/12/19 Javascript
drag-and-drop实现图片浏览器预览
2015/08/06 Javascript
jQuery实现带有动画效果的回到顶部和底部代码
2015/11/04 Javascript
javascript省市区三级联动下拉框菜单实例演示
2015/11/29 Javascript
AngularJS实现全选反选功能
2015/12/08 Javascript
基于BootStrap Metronic开发框架经验小结【三】下拉列表Select2插件的使用
2016/05/12 Javascript
js检查是否关闭浏览器的方法
2016/08/02 Javascript
js获取指定时间的前几秒
2017/04/05 Javascript
JavaScript分步实现一个出生日期的正则表达式
2018/03/22 Javascript
微信小程序的线程架构【推荐】
2019/05/14 Javascript
微信小程序全局变量的设置、使用、修改过程解析
2019/09/24 Javascript
layui上传图片到服务器的非项目目录下的方法
2019/09/26 Javascript
实现vuex原理的示例
2020/10/21 Javascript
写一个Vue loading 插件
2020/11/09 Javascript
python使用正则表达式替换匹配成功的组
2017/11/17 Python
利用python 更新ssh 远程代码 操作远程服务器的实现代码
2018/02/08 Python
python按综合、销量排序抓取100页的淘宝商品列表信息
2018/02/24 Python
Python中的单继承与多继承实例分析
2018/05/10 Python
在Python运行时动态查看进程内部信息的方法
2019/02/22 Python
Python 实现自动导入缺失的库
2019/10/29 Python
Python嵌套函数,作用域与偏函数用法实例分析
2019/12/26 Python
CSS3地图动态实例代码(圆圈向外扩散)
2018/06/15 HTML / CSS
乌克兰在线电子产品商店:MTA
2019/11/14 全球购物
init进程的作用
2012/04/12 面试题
服装创业计划书范文
2014/02/05 职场文书
《玩具柜台前的孩子》教学反思
2014/02/13 职场文书
教师节校长致辞
2015/07/31 职场文书
小学音乐课教学反思
2016/02/18 职场文书
《棉鞋里的阳光》教学反思
2016/02/20 职场文书
MySQL8.0.24版本Release Note的一些改进点
2021/04/22 MySQL