使用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 后缀名判断限制代码
Mar 31 NodeJs
用nodejs访问ActiveX对象,以操作Access数据库为例。
Dec 15 NodeJs
nodejs教程之制作一个简单的文章发布系统
Nov 21 NodeJs
轻松创建nodejs服务器(8):非阻塞是如何实现的
Dec 18 NodeJs
nodejs URL模块操作URL相关方法介绍
Mar 03 NodeJs
Express与NodeJs创建服务器的两种方法
Feb 06 NodeJs
详解nodeJS中读写文件方法的区别
Mar 06 NodeJs
nodejs 图解express+supervisor+ejs的用法(推荐)
Sep 08 NodeJs
NodeJS实现自定义流的方法
Aug 01 NodeJs
Nodejs Express 通过log4js写日志到Logstash(ELK)
Aug 30 NodeJs
nodejs环境使用Typeorm连接查询Oracle数据
Dec 05 NodeJs
浅谈使用nodejs搭建web服务器的过程
Jul 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调用Oracle存储过程的方法
2008/09/12 PHP
简化php模板页面中分页代码的解析
2009/02/06 PHP
兼容多浏览器的字幕特效Marquee的通用js类
2008/07/20 Javascript
ExtJs GridPanel简单的增删改实现代码
2010/08/26 Javascript
JavaScript 高级篇之DOM文档,简单封装及调用、动态添加、删除样式(六)
2012/04/07 Javascript
关于js new Date() 出现NaN 的分析
2012/10/23 Javascript
很好用的js日历算法详细代码
2013/03/07 Javascript
jquery提取元素里的纯文本不包含span等里的内容
2013/09/30 Javascript
window.onresize 多次触发的解决方法
2013/11/08 Javascript
jquery实现焦点图片随机切换效果的方法
2015/03/12 Javascript
JavaScript中反正弦函数Math.asin()的使用简介
2015/06/14 Javascript
jquery点击缩略图切换视频播放特效代码分享
2015/09/15 Javascript
通过网页查看JS源码中汉字显示乱码的解决方法
2016/10/26 Javascript
node.js中http模块和url模块的简单介绍
2017/10/06 Javascript
微信端调取相册和摄像头功能,实现图片上传,并上传到服务器
2019/05/16 Javascript
Vue全局loading及错误提示的思路与实现
2019/08/09 Javascript
Vue通过provide inject实现组件通信
2020/09/03 Javascript
react的hooks的用法详解
2020/10/12 Javascript
vue+vant 上传图片需要注意的地方
2021/01/03 Vue.js
python里使用正则表达式的组嵌套实例详解
2017/10/24 Python
利用numpy和pandas处理csv文件中的时间方法
2018/04/19 Python
python 实现求解字符串集的最长公共前缀方法
2018/07/20 Python
Python3.5基础之变量、数据结构、条件和循环语句、break与continue语句实例详解
2019/04/26 Python
Pytorch 扩展Tensor维度、压缩Tensor维度的方法
2020/09/09 Python
CSS3盒子模型详解
2013/04/24 HTML / CSS
英国领先的在线药房:Pharmacy First
2017/09/10 全球购物
了解AppleTalk协议吗
2014/04/01 面试题
《闻一多先生的说和做》教学反思
2014/04/28 职场文书
授权委托书格式
2014/07/31 职场文书
写给领导的感谢信
2015/01/22 职场文书
2015大学生求职信范文
2015/03/20 职场文书
2015年语文教学工作总结
2015/05/25 职场文书
宾馆卫生管理制度
2015/08/06 职场文书
2016年教师节贺卡寄语
2015/12/04 职场文书
详解python的内存分配机制
2021/05/10 Python
Golang的继承模拟实例
2021/06/30 Golang