使用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下打包模块archiver详解
Dec 03 NodeJs
轻松创建nodejs服务器(6):作出响应
Dec 18 NodeJs
轻松创建nodejs服务器(7):阻塞操作的实现
Dec 18 NodeJs
NodeJS使用jQuery选择器操作DOM
Feb 13 NodeJs
nodejs和php实现图片访问实时处理
Jan 05 NodeJs
Nodejs回调加超时限制两种实现方法
Jun 09 NodeJs
nodejs后台集成ueditor富文本编辑器的实例
Jul 11 NodeJs
NodeJS简单实现WebSocket功能示例
Feb 10 NodeJs
nodejs 生成和导出 word的实例代码
Jul 31 NodeJs
webpack打包nodejs项目的方法
Sep 26 NodeJs
nodejs更新package.json中的dependencies依赖到最新版本的方法
Oct 10 NodeJs
详解nodejs解压版安装和配置(带有搭建前端项目脚手架)
Dec 06 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读取目录下所有文件的代码
2008/01/07 PHP
PHP文件上传原理简单分析
2011/05/29 PHP
ThinkPHP分页类使用详解
2014/03/05 PHP
PHP采用自定义函数实现遍历目录下所有文件的方法
2014/08/19 PHP
深入研究PHP中的preg_replace和代码执行
2018/08/15 PHP
PHP simplexml_load_string()函数实例讲解
2019/02/03 PHP
Laravel 修改默认日志文件名称和位置的例子
2019/10/17 PHP
两个比较有用的Javascript工具函数代码
2010/02/17 Javascript
jquery select动态加载选择(兼容各种浏览器)
2013/02/01 Javascript
jquery select 设置默认选中的示例代码
2014/02/07 Javascript
jQuery插件jRumble实现网页元素抖动
2015/06/05 Javascript
js计算文本框输入的字符数
2015/10/23 Javascript
基于Bootstrap实现的下拉菜单手机端不能选择菜单项的原因附解决办法
2016/07/22 Javascript
JavaScript模块化之使用requireJS按需加载
2017/04/12 Javascript
解决vue中无法动态修改jqgrid组件 url地址的问题
2018/03/01 Javascript
详解Chart.js轻量级图表库的使用经验
2018/05/22 Javascript
详解Webpack + ES6 最新环境搭建与配置
2018/06/04 Javascript
Angular5中状态管理的实现
2018/09/03 Javascript
vue-router 手势滑动触发返回功能
2018/09/30 Javascript
Python中使用PyHook监听鼠标和键盘事件实例
2014/07/18 Python
python实现批量改文件名称的方法
2015/05/25 Python
python 字典中文key处理,读取,比较方法
2018/07/06 Python
Python通过队列来实现进程间通信的示例
2020/10/14 Python
Python实现简单猜数字游戏
2021/02/03 Python
使用tkinter实现三子棋游戏
2021/02/25 Python
CSS3实现歌词进度文字颜色填充变化动态效果的思路详解
2020/06/02 HTML / CSS
html5记忆翻牌游戏实现思路及代码
2013/07/25 HTML / CSS
MyFrenchPharma中文网:最大的法国药妆平台
2016/10/07 全球购物
英国最大线上综合鞋类商城:Office
2017/12/08 全球购物
工商治理实习生的自我评价
2014/01/15 职场文书
建筑工程质量通病防治方案
2014/06/08 职场文书
文明城市创建标语
2014/06/16 职场文书
商务经理岗位职责
2014/07/30 职场文书
2014年计划生育工作总结
2014/11/14 职场文书
上市公司董事长岗位职责
2015/04/16 职场文书
opencv用VS2013调试时用Image Watch插件查看图片
2021/07/26 Python