Python手寫檔案伺服器延伸內容


應用上一篇的Python檔案伺服器,我們還可以寫一些不同的回應,像是..

1. 回應Client端要求HTML檔案

def responseHtmlFile(hdl, path):
    f = open(path, "rb")
    fs = os.fstat(f.fileno())
    hdl.send_response(200)
    hdl.send_header("Content-type", "text/html; charset=UTF-8")
    hdl.send_header("Content-Length", str(fs[6]))
    hdl.send_header("Last-Modified", hdl.date_time_string(fs.st_mtime))
    hdl.end_headers()
    shutil.copyfileobj(f, hdl.wfile)
    f.close()
    del f
用法:
responseHtmlFile(hdl, '/home/user/your_html_file.htm')

2. 回應Client端,要求轉址到另一個目標位置

def responseHttpRedirect(hdl, target):
    hdl.send_response(301)
    hdl.send_header("Location", target)
    hdl.end_headers()
用法:
responseHttpRedirect(hdl, 'http://www.google.com')

3. 把Client的request資訊parse後再回應給Client

def responseGetRequest(hdl):
    parsed = urlparse(hdl.path)
    hdl.send_response(200)
    hdl.send_header("Content-type", "text/html; charset=UTF-8")
    hdl.end_headers()
    hdl.wfile.write("<html><body><h1>got GET request</h1><p>")
    hdl.wfile.write(('scheme=%s<br/>' % parsed.scheme))
    hdl.wfile.write(('netloc=%s<br/>' % parsed.netloc))
    hdl.wfile.write(('path=%s<br/>' % parsed.path))
    hdl.wfile.write(('params=%s<br/>' % parsed.params))
    hdl.wfile.write(('query=%s<br/>' % parsed.query))
    hdl.wfile.write(('fragments=%s<br/>' % parsed.fragment))
    hdl.wfile.write("</p></body></html>")
用法:
responseGetRequest(hdl)

4. 接受使用者的檔案上傳

# 接受上傳需要使用表單網頁和POST方法,附在後面
# 這只是個小 DEMO, 不建議直接使用在真正的網站中, 需要多考量一些網路攻擊的問題
# UploadedFilPath是儲存上傳檔案的完整路徑def responsePostRequest(hdl):
    form = cgi.FieldStorage(
        fp=hdl.rfile,
        headers=hdl.headers,
        environ={
            'REQUEST_METHOD': 'POST',
            'CONTENT_TYPE': hdl.headers['Content-Type'],
        }
    )
    hdl.send_response(200)
    hdl.send_header("Content-type", "text/html; charset=UTF-8")
    hdl.end_headers()
    hdl.wfile.write("<html
><body><h1>got POST request</h1><p>")
    for name in form.keys():
        item = form[name]
        if item.filename:
            uploadfile = None
            try:
                uploadfile = open(UploadedFilPath, 'wb')
                uploadfile.write(item.file.read())
            except IOError:
                hdl.log_error("Uploading file IOError: %s", sys.exc_info())
            finally:
                if uploadfile:
                    hdl.log_message("clear uploadfile")
                    filelen = uploadfile.tell();
                    uploadfile.flush()
                    uploadfile.close()
                    del uploadfile
                else:
                    filelen = 0;
            hdl.wfile.write(
                'Uploaded {} as {!r} ({} bytes)<br/
>'.format(
                    name, item.filename, filelen)
            )
        else:
            hdl.wfile.write('{}={}
<br/>'.format(
                name, form[name].value))
    hdl.wfile.write("</p>
</body></html>");
用法:
在get部分加入回應搭配給使用者選擇檔案的網頁
在post部分加入處理的部分
    def do_GET(hdl):
        hdl.log_message("from %s req %s", hdl.client_address, hdl.path)
        try:
            if hdl.path == "/form.html":
                responseHtmlFile(hdl, HtmlFormFilPath)
    def do_POST(hdl):
        hdl.log_message("from %s req %s", hdl.client_address, hdl.path)
        try:
            if hdl.path.startswith("/form_proc"):
                responsePostRequest(hdl)
            else:
                hdl.log_error("invalid post operation")
                hdl.send_error(404)
                return None
        except:
            hdl.log_error("Unexpected error: %s", sys.exc_info())
            hdl.send_error(404)
            return None

搭配的表單form.html網頁
<html>
<head>
<title>html form</title>
</head>
<body>
<h1>POST method</h1>
<form id="postform" action="form_proc" method="post" enctype="multipart/form-data">
 附加檔案:<input name="uploadedfile" type="file"/><br/>
 <input type="submit" value="送出表單"/>
</form>
</body>
</html>

留言