• 基于python创建一个简单的HTTP-WEB服务器


    • 背景

    大多数情况下主机资源只有开发和测试相关人员可以登录直接操作,且有些特定情况“答辩、演示、远程”等这些场景下是无法直接登录主机的。web是所有终端用户都可以访问了,解决了人员权限与特定场景带来的问题。那么我们就来看看最简单的web服务器是怎么创建的~~

    • 具体实现

    首先搭建python环境,涉及问题请移步http://www.cnblogs.com/xnchll/p/6431664.html。python内建模块SimpleHTTPServer,源码如下路径是/usr/lib64/python2.6/SimpleHTTPServer.py,有兴趣可看看

      1 """Simple HTTP Server.
      2 
      3 This module builds on BaseHTTPServer by implementing the standard GET
      4 and HEAD requests in a fairly straightforward manner.
      5 
      6 """
      7 
      8 
      9 __version__ = "0.6"
     10 
     11 __all__ = ["SimpleHTTPRequestHandler"]
     12 
     13 import os
     14 import posixpath
     15 import BaseHTTPServer
     16 import urllib
     17 import cgi
     18 import sys
     19 import shutil
     20 import mimetypes
     21 try:
     22     from cStringIO import StringIO
     23 except ImportError:
     24     from StringIO import StringIO
     25 
     26 
     27 class SimpleHTTPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
     28 
     29     """Simple HTTP request handler with GET and HEAD commands.
     30 
     31     This serves files from the current directory and any of its
     32     subdirectories.  The MIME type for files is determined by
     33     calling the .guess_type() method.
     34 
     35     The GET and HEAD requests are identical except that the HEAD
     36     request omits the actual contents of the file.
     37 
     38     """
     39 
     40     server_version = "SimpleHTTP/" + __version__
     41 
     42     def do_GET(self):
     43         """Serve a GET request."""
     44         f = self.send_head()
     45         if f:
     46             self.copyfile(f, self.wfile)
     47             f.close()
     48 
     49     def do_HEAD(self):
     50         """Serve a HEAD request."""
     51         f = self.send_head()
     52         if f:
     53             f.close()
     54 
     55     def send_head(self):
     56         """Common code for GET and HEAD commands.
     57 
     58         This sends the response code and MIME headers.
     59 
     60         Return value is either a file object (which has to be copied
     61         to the outputfile by the caller unless the command was HEAD,
     62         and must be closed by the caller under all circumstances), or
     63         None, in which case the caller has nothing further to do.
     64 
     65         """
     66         path = self.translate_path(self.path)
     67         f = None
     68         if os.path.isdir(path):
     69             if not self.path.endswith('/'):
     70                 # redirect browser - doing basically what apache does
     71                 self.send_response(301)
     72                 self.send_header("Location", self.path + "/")
     73                 self.end_headers()
     74                 return None
     75             for index in "index.html", "index.htm":
     76                 index = os.path.join(path, index)
     77                 if os.path.exists(index):
     78                     path = index
     79                     break
     80             else:
     81                 return self.list_directory(path)
     82         ctype = self.guess_type(path)
     83         try:
     84             # Always read in binary mode. Opening files in text mode may cause
     85             # newline translations, making the actual size of the content
     86             # transmitted *less* than the content-length!
     87             f = open(path, 'rb')
     88         except IOError:
     89             self.send_error(404, "File not found")
     90             return None
     91         self.send_response(200)
     92         self.send_header("Content-type", ctype)
     93         fs = os.fstat(f.fileno())
     94         self.send_header("Content-Length", str(fs[6]))
     95         self.send_header("Last-Modified", self.date_time_string(fs.st_mtime))
     96         self.end_headers()
     97         return f
     98 
     99     def list_directory(self, path):
    100         """Helper to produce a directory listing (absent index.html).
    101 
    102         Return value is either a file object, or None (indicating an
    103         error).  In either case, the headers are sent, making the
    104         interface the same as for send_head().
    105 
    106         """
    107         try:
    108             list = os.listdir(path)
    109         except os.error:
    110             self.send_error(404, "No permission to list directory")
    111             return None
    112         list.sort(key=lambda a: a.lower())
    113         f = StringIO()
    114         displaypath = cgi.escape(urllib.unquote(self.path))
    115         f.write('<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">')
    116         f.write("<html>
    <title>creditAutoTest project  %s</title>
    " % displaypath)
    117         f.write("<body>
    <h2>Directory listing for %s</h2>
    " % displaypath)
    118         f.write("<hr>
    <ul>
    ")
    119         for name in list:
    120             fullname = os.path.join(path, name)
    121             displayname = linkname = name
    122             # Append / for directories or @ for symbolic links
    123             if os.path.isdir(fullname):
    124                 displayname = name + "/"
    125                 linkname = name + "/"
    126             if os.path.islink(fullname):
    127                 displayname = name + "@"
    128                 # Note: a link to a directory displays with @ and links with /
    129             f.write('<li><a href="%s">%s</a>
    '
    130                     % (urllib.quote(linkname), cgi.escape(displayname)))
    131         f.write("</ul>
    <hr>
    </body>
    </html>
    ")
    132         length = f.tell()
    133         f.seek(0)
    134         self.send_response(200)
    135         encoding = sys.getfilesystemencoding()
    136         self.send_header("Content-type", "text/html; charset=%s" % encoding)
    137         self.send_header("Content-Length", str(length))
    138         self.end_headers()
    139         return f
    140 
    141     def translate_path(self, path):
    142         """Translate a /-separated PATH to the local filename syntax.
    143 
    144         Components that mean special things to the local file system
    145         (e.g. drive or directory names) are ignored.  (XXX They should
    146         probably be diagnosed.)
    147 
    148         """
    149         # abandon query parameters
    150         path = path.split('?',1)[0]
    151         path = path.split('#',1)[0]
    152         path = posixpath.normpath(urllib.unquote(path))
    153         words = path.split('/')
    154         words = filter(None, words)
    155         path = os.getcwd()
    156         for word in words:
    157             drive, word = os.path.splitdrive(word)
    158             head, word = os.path.split(word)
    159             if word in (os.curdir, os.pardir): continue
    160             path = os.path.join(path, word)
    161         return path
    162 
    163     def copyfile(self, source, outputfile):
    164         """Copy all data between two file objects.
    165 
    166         The SOURCE argument is a file object open for reading
    167         (or anything with a read() method) and the DESTINATION
    168         argument is a file object open for writing (or
    169         anything with a write() method).
    170 
    171         The only reason for overriding this would be to change
    172         the block size or perhaps to replace newlines by CRLF
    173         -- note however that this the default server uses this
    174         to copy binary data as well.
    175 
    176         """
    177         shutil.copyfileobj(source, outputfile)
    178 
    179     def guess_type(self, path):
    180         """Guess the type of a file.
    181 
    182         Argument is a PATH (a filename).
    183 
    184         Return value is a string of the form type/subtype,
    185         usable for a MIME Content-type header.
    186 
    187         The default implementation looks the file's extension
    188         up in the table self.extensions_map, using application/octet-stream
    189         as a default; however it would be permissible (if
    190         slow) to look inside the data to make a better guess.
    191 
    192         """
    193 
    194         base, ext = posixpath.splitext(path)
    195         if ext in self.extensions_map:
    196             return self.extensions_map[ext]
    197         ext = ext.lower()
    198         if ext in self.extensions_map:
    199             return self.extensions_map[ext]
    200         else:
    201             return self.extensions_map['']
    202 
    203     if not mimetypes.inited:
    204         mimetypes.init() # try to read system mime.types
    205     extensions_map = mimetypes.types_map.copy()
    206     extensions_map.update({
    207         '': 'application/octet-stream', # Default
    208         '.py': 'text/plain',
    209         '.c': 'text/plain',
    210         '.h': 'text/plain',
    211         '.log':'text/plain',
    212         '.out':'text/plain',
    213         '.sql':'text/plain',
    214         '.conf':'text/plain'
    215         })
    216 
    217 
    218 def test(HandlerClass = SimpleHTTPRequestHandler,
    219          ServerClass = BaseHTTPServer.HTTPServer):
    220     BaseHTTPServer.test(HandlerClass, ServerClass)
    221 
    222 
    223 if __name__ == '__main__':
    224     test()
    View Code

    使用方式如下:

    1. 明确需要展示web的根目录,比如/user/src
    2. 了解SimpleHTTPServer模块的几个关键参数,只说一下web服务的启动端口port。比如python -m SimpleHTTPServer port
    3. 修改一下源码web说明和支撑多种文件格式等等:

     

    最后,启动web服务器:

    python -m SimpleHTTPServer 8009
    

     小建议,一般web服务都是常驻进程,这里建议也设置为常驻进程或者添加为linux系统服务。

    • 结果展示:

     

     

  • 相关阅读:
    Windows server 2008 R2充当路由器实现网络的互联(转)
    sqlserver内存释放心得
    收藏一个好用的base64编解码网址
    最后一篇,说好的开源来了!
    python五子棋
    flask使用原生ajax、不使用表单(Form)上传文件
    使用keras的LSTM进行预测----实战练习
    keras神经网络三个例子
    【强化学习】用pandas 与 numpy 分别实现 q-learning, saras, saras(lambda)算法
    【转】【强化学习】Deep Q Network(DQN)算法详解
  • 原文地址:https://www.cnblogs.com/xnchll/p/8472760.html
Copyright © 2020-2023  润新知