具有小(大)OOP问题的新Python无法解决:(
我下载了一个由BaseHTTPServer实现的网络服务器运行代码的示例到目前为止一切正常,我试图通过我的"外部"来调用do_GET方法。 class脚本停止使用错误消息:
Traceback (most recent call last):
File "/usr/lib/python2.7/SocketServer.py", line 290, in _handle_request_noblock
self.process_request(request, client_address)
File "/usr/lib/python2.7/SocketServer.py", line 318, in process_request
self.finish_request(request, client_address)
File "/usr/lib/python2.7/SocketServer.py", line 331, in finish_request
self.RequestHandlerClass(request, client_address, self)
File "/usr/lib/python2.7/SocketServer.py", line 652, in __init__
self.handle()
File "/usr/lib/python2.7/BaseHTTPServer.py", line 340, in handle
self.handle_one_request()
File "/usr/lib/python2.7/BaseHTTPServer.py", line 328, in handle_one_request
method()
File "./webserver.py", line 41, in do_GET
MyHTTPHandlerClass.m_HTTPRequestHandler.do_GET(self)
AttributeError: 'module' object has no attribute 'do_GET'
解决问题的最佳方法是什么?谢谢!
webserver.py
#!/usr/bin/env python2.7
# -*- coding: utf-8 -*-
import argparse
import HTTPRequestHandler
import BaseHTTPServer
import logging
import os
import sys
def make_request_handler_class(opts):
MyHTTPRequestHandler = HTTPRequestHandler
MyHTTPRequestHandler.m_opts = opts
return MyHTTPRequestHandler
def make_http_handler_class(opts, localHTTPRequestHandler):
'''
Factory to make the request handler and add arguments to it.
It exists to allow the handler to access the opts.path variable
locally.
'''
class MyHTTPHandlerClass(BaseHTTPServer.BaseHTTPRequestHandler):
m_opts = opts
m_HTTPRequestHandler = localHTTPRequestHandler
def do_HEAD(self):
'''
Handle a HEAD request.
'''
logging.debug('HEADER %s' % (self.path))
self.send_response(200)
self.send_header('Content-type', 'text/html')
self.end_headers()
def do_GET(self):
MyHTTPHandlerClass.m_HTTPRequestHandler.do_GET(self)
return MyHTTPHandlerClass
def err(msg):
'''
Report an error message and exit.
'''
print('ERROR: %s' % (msg))
sys.exit(1)
def getopts():
'''
Get the command line options.
'''
# Get the help from the module documentation.
this = os.path.basename(sys.argv[0])
description = ('description:%s' % '\n '.join(__doc__.split('\n')))
epilog = ' '
rawd = argparse.RawDescriptionHelpFormatter
parser = argparse.ArgumentParser(formatter_class=rawd,
description=description,
epilog=epilog)
parser.add_argument('-d', '--daemonize',
action='store',
type=str,
default='.',
metavar='DIR',
help='daemonize this process, store the 3 run files (.log, .err, .pid) in DIR (default "%(default)s")')
parser.add_argument('-H', '--host',
action='store',
type=str,
default='localhost',
help='hostname, default=%(default)s')
parser.add_argument('-l', '--level',
action='store',
type=str,
default='info',
choices=['notset', 'debug', 'info', 'warning', 'error', 'critical',],
help='define the logging level, the default is %(default)s')
parser.add_argument('--no-dirlist',
action='store_true',
help='disable directory listings')
parser.add_argument('-p', '--port',
action='store',
type=int,
default=8080,
help='port, default=%(default)s')
parser.add_argument('-r', '--rootdir',
action='store',
type=str,
default=os.path.abspath('.'),
help='web directory root that contains the HTML/CSS/JS files %(default)s')
parser.add_argument('-v', '--verbose',
action='count',
help='level of verbosity')
parser.add_argument('-V', '--version',
action='version',
version='%(prog)s - v' + VERSION)
opts = parser.parse_args()
opts.rootdir = os.path.abspath(opts.rootdir)
if not os.path.isdir(opts.rootdir):
err('Root directory does not exist: ' + opts.rootdir)
if opts.port < 1 or opts.port > 65535:
err('Port is out of range [1..65535]: %d' % (opts.port))
return opts
def httpd(opts):
'''
HTTP server
'''
RequestHandlerClass = make_request_handler_class(opts)
HTTPHandlerClass = make_http_handler_class(opts, RequestHandlerClass)
server = BaseHTTPServer.HTTPServer((opts.host, opts.port), HTTPHandlerClass)
logging.info('Server starting %s:%s (level=%s)' % (opts.host, opts.port, opts.level))
try:
server.serve_forever()
except KeyboardInterrupt:
pass
server.server_close()
logging.info('Server stopping %s:%s' % (opts.host, opts.port))
def get_logging_level(opts):
'''
Get the logging levels specified on the command line.
The level can only be set once.
'''
if opts.level == 'notset':
return logging.NOTSET
elif opts.level == 'debug':
return logging.DEBUG
elif opts.level == 'info':
return logging.INFO
elif opts.level == 'warning':
return logging.WARNING
elif opts.level == 'error':
return logging.ERROR
elif opts.level == 'critical':
return logging.CRITICAL
def daemonize(opts):
'''
Daemonize this process.
CITATION: http://stackoverflow.com/questions/115974/what-would-be-the-simplest-way-to-daemonize-a-python-script-in-linux
'''
if os.path.exists(opts.daemonize) is False:
err('directory does not exist: ' + opts.daemonize)
if os.path.isdir(opts.daemonize) is False:
err('not a directory: ' + opts.daemonize)
bname = 'webserver-%s-%d' % (opts.host, opts.port)
outfile = os.path.abspath(os.path.join(opts.daemonize, bname + '.log'))
errfile = os.path.abspath(os.path.join(opts.daemonize, bname + '.err'))
pidfile = os.path.abspath(os.path.join(opts.daemonize, bname + '.pid'))
if os.path.exists(pidfile):
err('pid file exists, cannot continue: ' + pidfile)
if os.path.exists(outfile):
os.unlink(outfile)
if os.path.exists(errfile):
os.unlink(errfile)
if os.fork():
sys.exit(0) # exit the parent
os.umask(0)
os.setsid()
if os.fork():
sys.exit(0) # exit the parent
print('daemon pid %d' % (os.getpid()))
sys.stdout.flush()
sys.stderr.flush()
stdin = file('/dev/null', 'r')
stdout = file(outfile, 'a+')
stderr = file(errfile, 'a+', 0)
os.dup2(stdin.fileno(), sys.stdin.fileno())
os.dup2(stdout.fileno(), sys.stdout.fileno())
os.dup2(stderr.fileno(), sys.stderr.fileno())
with open(pidfile, 'w') as ofp:
ofp.write('%i' % (os.getpid()))
def main():
''' main entry '''
opts = getopts()
if opts.daemonize:
daemonize(opts)
logging.basicConfig(format='%(asctime)s [%(levelname)s] %(message)s', level=get_logging_level(opts))
httpd(opts)
if __name__ == '__main__':
main() # this allows library functionality
HTTPRequestHandler.py
#!/usr/bin/env python2.7
# -*- coding: utf-8 -*-
import cgi
import logging
import os
'''
Factory to make the request handler and add arguments to it.
It exists to allow the handler to access the opts.path variable
locally.
'''
class HTTPRequestHandler:
def do_GET(BaseHTTPRequestHandler):
m_BaseHTTPRequest = BaseHTTPRequestHandler
# Parse out the arguments.
# The arguments follow a '?' in the URL. Here is an example:
# http://example.com?arg1=val1
args = {}
idx = m_BaseHTTPRequest.path.find('?')
if idx >= 0:
rpath = m_BaseHTTPRequest.path[:idx]
args = cgi.parse_qs(m_BaseHTTPRequest.path[idx+1:])
else:
rpath = m_BaseHTTPRequest.path
# Print out logging information about the path and args.
if 'content-type' in m_BaseHTTPRequest.headers:
ctype, _ = cgi.parse_header(m_BaseHTTPRequest.headers['content-type'])
logging.debug('TYPE %s' % (ctype))
logging.debug('PATH %s' % (rpath))
logging.debug('ARGS %d' % (len(args)))
if len(args):
i = 0
for key in sorted(args):
logging.debug('ARG[%d] %s=%s' % (i, key, args[key]))
i += 1
# Check to see whether the file is stored locally,
# if it is, display it.
# Get the file path.
path = HTTPRequestHandler.m_opts.rootdir + rpath
dirpath = None
logging.debug('FILE %s' % (path))
# If it is a directory look for index.html
# or process it directly if there are 3
# trailing slashed.
if rpath[-3:] == '///':
dirpath = path
elif os.path.exists(path) and os.path.isdir(path):
dirpath = path # the directory portion
index_files = ['/index.html', '/index.htm', ]
for index_file in index_files:
tmppath = path + index_file
if os.path.exists(tmppath):
path = tmppath
break
# Allow the user to type "///" at the end to see the
# directory listing.
if os.path.exists(path) and os.path.isfile(path):
# This is valid file, send it as the response
# after determining whether it is a type that
# the server recognizes.
_, ext = os.path.splitext(path)
ext = ext.lower()
content_type = {
'.css': 'text/css',
'.gif': 'image/gif',
'.htm': 'text/html',
'.html': 'text/html',
'.jpeg': 'image/jpeg',
'.jpg': 'image/jpg',
'.js': 'text/javascript',
'.png': 'image/png',
'.text': 'text/plain',
'.txt': 'text/plain',
}
# If it is a known extension, set the correct
# content type in the response.
if ext in content_type:
m_BaseHTTPRequest.send_response(200) # OK
m_BaseHTTPRequest.send_header('Content-type', content_type[ext])
m_BaseHTTPRequest.end_headers()
with open(path) as ifp:
m_BaseHTTPRequest.wfile.write(ifp.read())
else:
# Unknown file type or a directory.
# Treat it as plain text.
m_BaseHTTPRequest.send_response(200) # OK
m_BaseHTTPRequest.send_header('Content-type', 'text/plain')
m_BaseHTTPRequest.end_headers()
with open(path) as ifp:
m_BaseHTTPRequest.wfile.write(ifp.read())
elif 1 == 2:
# There is special handling for http://127.0.0.1/info. That URL
# displays some internal information.
if m_BaseHTTPRequest.path == '/info' or m_BaseHTTPRequest.path == '/info/':
m_BaseHTTPRequest.send_response(200) # OK
m_BaseHTTPRequest.send_header('Content-type', 'text/html')
m_BaseHTTPRequest.end_headers()
m_BaseHTTPRequest.info()
else:
if dirpath is None or m_BaseHTTPRequest.m_opts.no_dirlist == True:
# Invalid file path, respond with a server access error
m_BaseHTTPRequest.send_response(500) # generic server error for now
m_BaseHTTPRequest.send_header('Content-type', 'text/html')
m_BaseHTTPRequest.end_headers()
m_BaseHTTPRequest.wfile.write('<html>')
m_BaseHTTPRequest.wfile.write(' <head>')
m_BaseHTTPRequest.wfile.write(' <title>Server Access Error</title>')
m_BaseHTTPRequest.wfile.write(' </head>')
m_BaseHTTPRequest.wfile.write(' <body>')
m_BaseHTTPRequest.wfile.write(' <p>Server access error.</p>')
m_BaseHTTPRequest.wfile.write(' <p>%r</p>' % (repr(m_BaseHTTPRequest.path)))
m_BaseHTTPRequest.wfile.write(' <p><a href="%s">Back</a></p>' % (rpath))
m_BaseHTTPRequest.wfile.write(' </body>')
m_BaseHTTPRequest.wfile.write('</html>')
else:
# List the directory contents. Allow simple navigation.
logging.debug('DIR %s' % (dirpath))
m_BaseHTTPRequest.send_response(200) # OK
m_BaseHTTPRequest.send_header('Content-type', 'text/html')
m_BaseHTTPRequest.end_headers()
m_BaseHTTPRequest.wfile.write('<html>')
m_BaseHTTPRequest.wfile.write(' <head>')
m_BaseHTTPRequest.wfile.write(' <title>%s</title>' % (dirpath))
m_BaseHTTPRequest.wfile.write(' </head>')
m_BaseHTTPRequest.wfile.write(' <body>')
m_BaseHTTPRequest.wfile.write(' <a href="%s">Home</a><br>' % ('/'));
# Make the directory path navigable.
dirstr = ''
href = None
for seg in rpath.split('/'):
if href is None:
href = seg
else:
href = href + '/' + seg
dirstr += '/'
dirstr += '<a href="%s">%s</a>' % (href, seg)
m_BaseHTTPRequest.wfile.write(' <p>Directory: %s</p>' % (dirstr))
# Write out the simple directory list (name and size).
m_BaseHTTPRequest.wfile.write(' <table border="0">')
m_BaseHTTPRequest.wfile.write(' <tbody>')
fnames = ['..']
fnames.extend(sorted(os.listdir(dirpath), key=str.lower))
for fname in fnames:
m_BaseHTTPRequest.wfile.write(' <tr>')
m_BaseHTTPRequest.wfile.write(' <td align="left">')
path = rpath + '/' + fname
fpath = os.path.join(dirpath, fname)
if os.path.isdir(path):
m_BaseHTTPRequest.wfile.write(' <a href="%s">%s/</a>' % (path, fname))
else:
m_BaseHTTPRequest.wfile.write(' <a href="%s">%s</a>' % (path, fname))
m_BaseHTTPRequest.wfile.write(' <td> </td>')
m_BaseHTTPRequest.wfile.write(' </td>')
m_BaseHTTPRequest.wfile.write(' <td align="right">%d</td>' % (os.path.getsize(fpath)))
m_BaseHTTPRequest.wfile.write(' </tr>')
m_BaseHTTPRequest.wfile.write(' </tbody>')
m_BaseHTTPRequest.wfile.write(' </table>')
m_BaseHTTPRequest.wfile.write(' </body>')
m_BaseHTTPRequest.wfile.write('</html>')
代码文件:
webserver.py https://pastebin.com/P1sy67gE
HTTPRequestHandler.py https://pastebin.com/4KX3XE8b