使用Python 实现一个简单的http服务器

Python运行环境:Ubuntu Ubuntu 18.04.1 LTS
本文仅用于记录学习和分析Python的过程,Python还有很多搭建web服务器的框架本文都不涉及。

最简单的方式

执行命令:

 $ python -m SimpleHTTPServer  
//如果不指定端口,默认使用8000

然后在浏览器上输入:

http://localhost:8000/ 
//把localhost改成Linux主机ip

然后Duang~~~
在这里插入图片描述

网页上显示出这个,那个A_File是我在Linux下运行Python文件里面的一个文件。

什么,就这么简单?好吧,作为一个Linux C程序员,不得不说,我得研究一下源码。

SimpleHTTPServer

网页哪来的?

最基本的理解是,有网页就得有html文件,而且很显而易见的是,这个网页看上去是调整过格式的。

开始的想法

一开始想到就是在我的Linux环境里是有一个这样的html文件存在的,在使用SimpleHTTPServer模块时会找到它,并且推给前端。然后就在Python安装路径和系统里找这个文件,最后都把以前玩过的Apache和Tomcat里面的html都翻出来了也没对上号。。。

换个思路

先考虑两点:
1. 打开网页时HTTP Server会有这样的信息:“GET / HTTP/1.1” 200 -。说明打开网页的时候执行的是GET请求(这个好像是理所当然的)。
2. 从浏览器上查看网页源码:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"><html>
<title>Directory listing for /</title>
<body>
<h2>Directory listing for /</h2>
<hr>
<ul>
<li><a href="A_File">A_File</a>
</ul>
<hr>
</body>
</html>

接下来从源码的角度分析一下:
在我的Linux系统中找到SimpleHTTPServer模块源码(感兴趣的源码自行查找),查看do_GET() 方法:

def do_GET(self):
"""Serve a GET request."""
f = self.send_head()
if f:
    try:
        self.copyfile(f, self.wfile)
    finally:
        f.close()

这么一看应该是要看一下send_head() 方法做了什么,里面有这样一段代码:

path = self.translate_path(self.path)
f = None
if os.path.isdir(path):
    parts = urlparse.urlsplit(self.path)
    if not parts.path.endswith('/'):
        # redirect browser - doing basically what apache does
        self.send_response(301)
        new_parts = (parts[0], parts[1], parts[2] + '/',
                     parts[3], parts[4])
        new_url = urlparse.urlunsplit(new_parts)
        self.send_header("Location", new_url)
        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)

主要看一下for循环的作用,实际上是在当前路径下查找index.html, index.htm 如果没找到就return到 list_directory() 方法,紧接着就在list_directory() 方法里看到这样的代码:

 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<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")

很显然,这个段代码刚好对应到了上面贴的网页源码。现在真相大白了,在打开网页时do_GET() 方法会调用 list_directory() 创建一个html出来给前端显示。

验证一下

虽然从代码的逻辑上分析完了,但是总觉得怪怪的,还是要自己跑一下代码才放心啊。

使用Python的好处就是可以方便的进行验证,这一点就比C方便的多。
首先把SimpleHTTPServer.py从源码路径里copy出来放到与A_File同一路径下,然后执行命令:

$ python SimpleHTTPServer.py

然后用服务器ip打开网页会看到:
在这里插入图片描述
网页可以正常打开,显示的也正是预期的结果,说明刚刚的操作是正确的。
这也正是用Python的优势所在,这个源码文件其实是需要BaseHTTPServer 等模块支持的,但是我并没有把这个模块copy过来。当然也是因为在Linux环境下安装Python的时候就已经配置好环境变量了。当然也可以类比Shell。

根据上面的分析,如果再当前路径下有html文件会怎么样呢?
创建一个index.html文件,里面加上一句"Hello World!",然后启动脚本在打开网页会显示如下:
在这里插入图片描述
(万年的Hello World???)
这说明之前对那个for 循环部分的代码分析是没错的。同样的可以把list_directory() 方法里面的StringIO 打印出来也会对上面的介绍进行验证。

至于在GET请求时 “GET / HTTP/1.1” 200 - 这个信息打印是怎么打印出来的呢,可以把BaseHTTPServer 模块源码copy过来做一下验证,里面有个log_message() 方法,具体代码逻辑就不在这里分析了。

也就是说,所有的现象只要仔细分析一下源码都能找到根源。

为什么要用Python搭建,因为如果单纯的想要从服务器上下载文件,用Python 的SimpleHTTPServer 模块搭建一个服务器要比搭建ftp或者是tftp简单的多。
但是这个单纯的执行一下 命令python -m SimpleHTTPServer,只能实现文件的下载功能,如果想要实现文件上传功能可以参考:https://github.com/tualatrix/tools/blob/master/SimpleHTTPServerWithUpload.py 这里面实现了POST请求功能。

  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值