对于Python 2,简单搭建Web服务器,只需在需要搭建Web服务器的目录(如C:/ 或 /home/klchang/)下,输入如下命令:

python -m SimpleHTTPServer 8080

含义为使用 8080端口的创建Web服务器,可以使用浏览器 http://127.0.0.1:8080 或 将 127.0.0.1 替换为本机的外部IP地址,进行访问。

对于Python 3,其创建Web服务器的等价命令,如下:

python3 -m http.server 8080

补充 - 2018.8.11:

上面的命令,只是简单地实现访问当前目录文件的功能,如果需要增加上传文件功能,则可参考如下的 Python 代码 (只支持 Python 2.x):

# SimpleHTTPServerWithUpload.py
# This code tweaked from https://github.com/tualatrix/tools/blob/master/SimpleHTTPServerWithUpload.py
"""Simple HTTP Server With Upload.
This module builds on BaseHTTPServer by implementing the standard GET
and HEAD requests in a fairly straightforward manner.
""" __version__ = "0.1"
__all__ = ["SimpleHTTPRequestHandler"]
__author__ = "bones7456"
__home_page__ = "http://li2z.cn/" import os
import posixpath
import BaseHTTPServer
import urllib
import cgi
import shutil
import mimetypes
import re
try:
from cStringIO import StringIO
except ImportError:
from StringIO import StringIO class SimpleHTTPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler): """Simple HTTP request handler with GET/HEAD/POST commands.
This serves files from the current directory and any of its
subdirectories. The MIME type for files is determined by
calling the .guess_type() method. And can reveive file uploaded
by client.
The GET/HEAD/POST requests are identical except that the HEAD
request omits the actual contents of the file.
""" server_version = "SimpleHTTPWithUpload/" + __version__ def do_GET(self):
"""Serve a GET request."""
f = self.send_head()
if f:
self.copyfile(f, self.wfile)
f.close() def do_HEAD(self):
"""Serve a HEAD request."""
f = self.send_head()
if f:
f.close() def do_POST(self):
"""Serve a POST request."""
r, info = self.deal_post_data()
print r, info, "by: ", self.client_address
f = StringIO()
f.write('<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">')
f.write("<html>\n<title>Upload Result Page</title>\n")
f.write("<body>\n<h2>Upload Result Page</h2>\n")
f.write("<hr>\n")
if r:
f.write("<strong>Success:</strong> ")
else:
f.write("<strong>Failed:</strong> ")
f.write(info)
f.write("<br><a href=\"%s\">back</a>" % self.headers['referer'])
f.write("<hr><small>Powered By: bones7456, check new version at ")
f.write("<a href=\"http://li2z.cn/?s=SimpleHTTPServerWithUpload\">")
f.write("here</a>.</small></body>\n</html>\n")
length = f.tell()
f.seek(0)
self.send_response(200)
self.send_header("Content-type", "text/html")
self.send_header("Content-Length", str(length))
self.end_headers()
if f:
self.copyfile(f, self.wfile)
f.close() def deal_post_data(self):
boundary = self.headers.plisttext.split("=")[1]
remainbytes = int(self.headers['content-length'])
line = self.rfile.readline()
remainbytes -= len(line)
if not boundary in line:
return (False, "Content NOT begin with boundary")
line = self.rfile.readline()
remainbytes -= len(line)
fn = re.findall(r'Content-Disposition.*name="file"; filename="(.*)"', line)
if not fn:
return (False, "Can't find out file name...")
elif not fn[0]:
return (False, "No file chosen.")
path = self.translate_path(self.path)
fn = os.path.join(path, fn[0])
while os.path.exists(fn):
fn += "_"
line = self.rfile.readline()
remainbytes -= len(line)
line = self.rfile.readline()
remainbytes -= len(line)
try:
out = open(fn, 'wb')
except IOError:
return (False, "Can't create file to write, do you have permission to write?") if line.strip():
preline = line
else:
preline = self.rfile.readline()
remainbytes -= len(preline)
while remainbytes > 0:
line = self.rfile.readline()
remainbytes -= len(line)
if boundary in line:
preline = preline[0:-1]
if preline.endswith('\r'):
preline = preline[0:-1]
out.write(preline)
out.close()
return (True, "File '%s' upload success!" % fn)
else:
out.write(preline)
preline = line
return (False, "Unexpect Ends of data.") def send_head(self):
"""Common code for GET and HEAD commands.
This sends the response code and MIME headers.
Return value is either a file object (which has to be copied
to the outputfile by the caller unless the command was HEAD,
and must be closed by the caller under all circumstances), or
None, in which case the caller has nothing further to do.
"""
path = self.translate_path(self.path)
f = None
if os.path.isdir(path):
if not self.path.endswith('/'):
# redirect browser - doing basically what apache does
self.send_response(301)
self.send_header("Location", self.path + "/")
self.end_headers()
return None
for index in "index.html", "index.htm":
index = os.path.join(path, index)
if os.path.exists(index):
path = index
break
else:
return self.list_directory(path)
ctype = self.guess_type(path)
try:
# Always read in binary mode. Opening files in text mode may cause
# newline translations, making the actual size of the content
# transmitted *less* than the content-length!
f = open(path, 'rb')
except IOError:
self.send_error(404, "File not found")
return None
self.send_response(200)
self.send_header("Content-type", ctype)
fs = os.fstat(f.fileno())
self.send_header("Content-Length", str(fs[6]))
self.send_header("Last-Modified", self.date_time_string(fs.st_mtime))
self.end_headers()
return f def list_directory(self, path):
"""Helper to produce a directory listing (absent index.html).
Return value is either a file object, or None (indicating an
error). In either case, the headers are sent, making the
interface the same as for send_head().
"""
try:
list = os.listdir(path)
except os.error:
self.send_error(404, "No permission to list directory")
return None
list.sort(key=lambda a: a.lower())
f = StringIO()
displaypath = cgi.escape(urllib.unquote(self.path))
f.write('<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">')
f.write("<html>\n<title>Directory listing for %s</title>\n" % displaypath)
f.write("<body>\n<h2>Directory listing for %s</h2>\n" % displaypath)
f.write("<hr>\n")
f.write("<form ENCTYPE=\"multipart/form-data\" method=\"post\">")
f.write("<input name=\"file\" type=\"file\"/>")
f.write("<input type=\"submit\" value=\"upload\"/></form>\n")
f.write("<hr>\n<ul>\n")
for name in list:
fullname = os.path.join(path, name)
displayname = linkname = name
# Append / for directories or @ for symbolic links
if os.path.isdir(fullname):
displayname = name + "/"
linkname = name + "/"
if os.path.islink(fullname):
displayname = name + "@"
# Note: a link to a directory displays with @ and links with /
f.write('<li><a href="%s">%s</a>\n'
% (urllib.quote(linkname), cgi.escape(displayname)))
f.write("</ul>\n<hr>\n</body>\n</html>\n")
length = f.tell()
f.seek(0)
self.send_response(200)
self.send_header("Content-type", "text/html")
self.send_header("Content-Length", str(length))
self.end_headers()
return f def translate_path(self, path):
"""Translate a /-separated PATH to the local filename syntax.
Components that mean special things to the local file system
(e.g. drive or directory names) are ignored. (XXX They should
probably be diagnosed.)
"""
# abandon query parameters
path = path.split('?',1)[0]
path = path.split('#',1)[0]
path = posixpath.normpath(urllib.unquote(path))
words = path.split('/')
words = filter(None, words)
path = os.getcwd()
for word in words:
drive, word = os.path.splitdrive(word)
head, word = os.path.split(word)
if word in (os.curdir, os.pardir): continue
path = os.path.join(path, word)
return path def copyfile(self, source, outputfile):
"""Copy all data between two file objects.
The SOURCE argument is a file object open for reading
(or anything with a read() method) and the DESTINATION
argument is a file object open for writing (or
anything with a write() method).
The only reason for overriding this would be to change
the block size or perhaps to replace newlines by CRLF
-- note however that this the default server uses this
to copy binary data as well.
"""
shutil.copyfileobj(source, outputfile) def guess_type(self, path):
"""Guess the type of a file.
Argument is a PATH (a filename).
Return value is a string of the form type/subtype,
usable for a MIME Content-type header.
The default implementation looks the file's extension
up in the table self.extensions_map, using application/octet-stream
as a default; however it would be permissible (if
slow) to look inside the data to make a better guess.
""" base, ext = posixpath.splitext(path)
if ext in self.extensions_map:
return self.extensions_map[ext]
ext = ext.lower()
if ext in self.extensions_map:
return self.extensions_map[ext]
else:
return self.extensions_map[''] if not mimetypes.inited:
mimetypes.init() # try to read system mime.types
extensions_map = mimetypes.types_map.copy()
extensions_map.update({
'': 'application/octet-stream', # Default
'.py': 'text/plain',
'.c': 'text/plain',
'.h': 'text/plain',
}) def test(HandlerClass = SimpleHTTPRequestHandler,
ServerClass = BaseHTTPServer.HTTPServer):
BaseHTTPServer.test(HandlerClass, ServerClass) if __name__ == '__main__':
test()

将其保存为 SimpleHTTPServerWithUpload.py,采用如下方式创建使用 8080 端口的 Web 服务器:

python SimpleHTTPServerWithUpload.py 

参考资料:

1、非常简单的Python HTTP服务

http://coolshell.cn/articles/1480.html

2、What is the Python 3 equivalent of “python -m SimpleHTTPServer”

http://stackoverflow.com/questions/7943751/what-is-the-python-3-equivalent-of-python-m-simplehttpserver

python简单搭建HTTP Web服务器的更多相关文章

  1. Golang学习-第二篇 搭建一个简单的Go Web服务器

    序言 由于本人一直从事Web服务器端的程序开发,所以在学习Golang也想从Web这里开始学起,如果对Golang还不太清楚怎么搭建环境的朋友们可以参考我的上一篇文章 Golang的简单介绍及Wind ...

  2. python自带的web服务器

    python自带的web服务器 python自带的包可以建立简单的web服务器 BaseHTTPServer 提供基本的web服务和处理类 SimpleHTTPServer 包含执行get请求的Sim ...

  3. 分享关于搭建高性能WEB服务器的一篇文章

    这篇文章主要介绍了Centos5.4+Nginx-0.8.50+UWSGI-0.9.6.2+Django-1.2.3搭建高性能WEB服务器的相关资料,需要的朋友可以参考下(http://m.0813s ...

  4. python 简单搭建非阻塞式单进程,select模式,epoll模式服务

    由于经常被抓取文章内容,在此附上博客文章网址:,偶尔会更新某些出错的数据或文字,建议到我博客地址 :  --> 点击这里 可以看我的上篇文章 <python 简单搭建阻塞式单进程,多进程, ...

  5. 如何搭建一个WEB服务器项目(二)—— 对数据库表进行基本的增删改查操作

    使用HibernateTemplate进行增删改查操作 观前提示:本系列文章有关服务器以及后端程序这些概念,我写的全是自己的理解,并不一定正确,希望不要误人子弟.欢迎各位大佬来评论区提出问题或者是指出 ...

  6. 一个简单的Java web服务器实现

    前言 一个简单的Java web服务器实现,比较简单,基于java.net.Socket和java.net.ServerSocket实现: 程序执行步骤 创建一个ServerSocket对象: 调用S ...

  7. JSP学习笔记(三):简单的Tomcat Web服务器

    注意:每次对Tomcat配置文件进行修改后,必须重启Tomcat 在E盘的DATA文件夹中创建TomcatDemo文件夹,并将Tomcat安装路径下的webapps/ROOT中的WEB-INF文件夹复 ...

  8. python 简单搭建阻塞式单进程,多进程,多线程服务

    由于经常被抓取文章内容,在此附上博客文章网址:,偶尔会更新某些出错的数据或文字,建议到我博客地址 :  --> 点击这里 我们可以通过这样子的方式去理解apache的工作原理 1 单进程TCP服 ...

  9. 搭建手机web服务器-----内网穿透(无需Root)

    搭建手机web服务器-----内网穿透(无需Root) 一.内网穿透部分 前言: 网上内网穿透的方法很多,像花生壳.Ngrok.Frp等等,但是大多都需要获取手机root权限 本文使用的软件是Term ...

随机推荐

  1. ipad和iphone的适配

    关于xib或者storybord下iphone的横竖屏的适配以及ipad的适配 ios8出现了Size Classes,解决了各种屏幕适配的问题,他把屏幕的宽和高分别分成了三种,把屏幕总共分成了九种情 ...

  2. DAO设计模式

    DAO设计模式 DAO设计模式简介: DAO设计模式可以减少代码量,增强程序的可移植性,提高代码的可读性. DAO(数据库操作对象)设计模式是 JavaEE 数据层的操作.主要由五部分组成: 1.数据 ...

  3. JuCheap V2.0响应式后台管理系统模板正式发布beta版本

    JuCheap V1.* 查看地址: http://blog.csdn.net/allenwdj/article/details/49155339 经过半年的努力,JuCheap后台通用响应式管理后台 ...

  4. IT软件技术人员的职位路线(从程序员到技术总监) - 部门管理经验谈

    以前写过一个文(IT从业者的职业道路(从程序员到部门经理) - 项目管理系列文章),主要介绍笔者的职业发展之路,不过该文需要后续了,因为笔者现在从事的是“产品经理”一职.从笔者的导航文([置顶]博文快 ...

  5. 数据库实战案例—————记一次TempDB暴增的问题排查

    前言 很多时候数据库的TempDB.日志等文件的暴增可能导致磁盘空间被占满,如果日常配置不到位,往往会导致数据库故障,业务被迫中断. 这种文件暴增很难排查,经验不足的一些运维人员可能更是无法排查具体原 ...

  6. 40GbE网络之后

    Ethernet Alliance 成员则有近90家公司,主要成员包括:网路晶片厂商Intel.Broadcom,网路设备商Cisco.Juniper.Brocade.Dell.QLogic,以及储存 ...

  7. 腾讯php经历

    12年毕业至今,一年C#,2年php,几个月node,因为一些原因再次离职,接到腾讯互娱的php面试电话,匆匆准备了一番,便去了科兴科技园腾讯的高大上办公楼. 1.笔试 试题大部分网上都有,例如: 用 ...

  8. PHP玩转微信公众平台自定义接口

    从微信公众平台开通自定义回复后,就一直在关注微信接口这一块,很想用自定义回复这块做个站长工具的查询,例如PR查询,备案查询等,输入网址信息,就能自动获取PR,获取备案信息,应该是一个不错的想法.不过以 ...

  9. ImportError: No module named 'requests'

    补充说明: 当前环境是在windows环境下 python版本是:python 3.4. 刚开始学习python,一边看书一边论坛里阅读感兴趣的代码, http://www.oschina.net/c ...

  10. MySQL高级特性

    MySQL管理 用户管理 CREATE USER username IDENTIFIED BY 'password'; 新建用户 CREATE USER@'%' IDENTIFIED BY 'pass ...