一.测试准备

先分别写一个简单httpserver 和一个html文件。html文件只是引入了 jquery, 后面测试用

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
</head>
<body>

</body>
</html>

python 是开启了最简单的一个 http服务 

#!/usr/bin/env python
# -*- coding: utf-8 -*-

# Project: httpserver_test
# File : main.py
# Author : Long.Xu <fangkailove@yeah.net>
# http://gnolux.blog.csdn.net
# QQ:26564303 weixin:wxgnolux
# Time : 2022/8/27 17:19
# Copyright 2022 Long.Xu All rights Reserved.
from http.server import BaseHTTPRequestHandler, test
import os


class TestRequestHandler(BaseHTTPRequestHandler):
def do_GET(self):
print("do_GET")
if self.path == '/':
txt = "do_GET Test body"
self.send_response_only(200)
self.send_header('Content-type', 'text/html')
self.end_headers()
self.wfile.write(txt.encode())
else:
self.send_error(404)

if __name__ == '__main__':
test(HandlerClass=TestRequestHandler)

python 脚本运行,会开启 127.0.0.1:8000   的http服务。

python http.server 的测试和常见问题解决方法_服务器

浏览器访问 http://127.0.0.1:8000 ,可以正常访问,返回结果也正确。

python http.server 的测试和常见问题解决方法_http_02

好了,在这个基础上我们来研究和测试几个问题。

二.测试问题1: 跨域访问问题

我们单独以文件方式打开html文件,并在chrome打开调试
$.ajax({url:'http://127.0.0.1:8000',type:'get',success:function (data) {
console.log(data)    
}})

正常情况,应该能打印出 do_GET test body , 但实际会报错,如下:

python http.server 的测试和常见问题解决方法_jquery_03

提示因为跨域策略被阻挡了,并未按预期的正常返回信息,这是因为我们现在是以本地文件的方式,访问一个远程服务(虽然是127.0.0.1),因为服务器不支持跨域访问,那服务器要怎么处理?服务器只需要接收到此类请求时,在header里加入一个访问许可标识。如下:

python http.server 的测试和常见问题解决方法_html_04

修改完后,重新运行脚本,浏览器再次测试,成功。

python http.server 的测试和常见问题解决方法_http.server_05

 三.测试其它HTTP动作

python http.server 的测试和常见问题解决方法_http.server_06

 按之前do_GET的方法,实作了do_PUT 应该是可以的,但为什么还是会报跨域的错误呢?我们看一下请求。实际上有两个请求:

python http.server 的测试和常见问题解决方法_http.server_07

首先是做了一个 OPTIONS 方法的请求,反回没有这个方法,也就是说除了get外其它方法(动作)首先会先做一个OPTIONS 的请求,来确认请求的动作是不是被允许的。 所以要先实作 OPTIONS动作。 python脚本加上以下代码:

def do_OPTIONS(self):
print("do_OPTIONS")
self.send_response_only(200, "ok")
self.send_header('Access-Control-Allow-Origin', '*')
self.end_headers()

再测试:

python http.server 的测试和常见问题解决方法_服务器_08

可以发现 第一个请求成功了,即options方法请求成功,但是put还是没有成功,报错 PUT 方法不被允许。 这个就是要在options方法内,服务器要没有返回相应的允许的动作 ,再修改 do_OPTIONS 方法 ,加入 self.send_header('Access-Control-Allow-Methods', 'PUT') 

def do_OPTIONS(self):
print("do_OPTIONS")
self.send_response_only(200, "ok")
self.send_header('Access-Control-Allow-Origin', '*')
self.send_header('Access-Control-Allow-Methods', 'PUT')
self.end_headers()

 再测试,如下,成功了。

python http.server 的测试和常见问题解决方法_html_09

我们再扩展一下思路,是不是只要在这里定义好允许的动作,我们可以随意定义超出http标准的动作呢。我们试一下,加一个TEST01动作,并实作一个 do_TEST01


self.send_header('Access-Control-Allow-Methods', 'PUT,TEST01'


python http.server 的测试和常见问题解决方法_html_10

 

python http.server 的测试和常见问题解决方法_http_11

 

python http.server 的测试和常见问题解决方法_http_12

还真的行哦。 结论就是只要 在options里返回允许的 method,服务器段也有相应的method处理程序那么完全可以自定义 http method. 

 三. 终端显示不想显示下面的log提示怎么办? 

python http.server 的测试和常见问题解决方法_html_13

这里我们可以改用         self.send_response_only(200)
来避免,但是有些地方只能用其它方法或者是基类的log产生的log,这种方法就无没办法了。其实可以把基类中 log_message 方法给继承重写了,就能避免输出了。

python http.server 的测试和常见问题解决方法_html_14

 四.http.server 里几个类的关系

python http.server 的测试和常见问题解决方法_html_15

 首先看 Server ,  Server 的职责是完成网络通信协议的基本功能,即底层通信有它负责,那么相应的 RequestHandler 就是负责协议以上的对接收数据的处理了。
Server 有 HTTPServer 是从TCPServer继承来的,ThreadingHTTPServer 对是继承自 HTTPServer,在它基础上增加了多线程处理机制,可以并行接收多客户端的请求。

ReqeustHandler 有 BaseHTTPRequestHandler 和 SimpleHTTPRequestHandler 后者实作了一些对文件的处理,完成了一般httpserver对文件的访问功能。

五.为什么 只要用 do_XXXX 的方式作一个方法,就能处理相应的方法请求呢?

这个奥秘就在于 BaseHTTPRequestHandler 里了。

python http.server 的测试和常见问题解决方法_jquery_16

python http.server 的测试和常见问题解决方法_服务器_17

是按前端传来的 command ,动态查找有没有相应的方法,如果有就调用的,这里充份发挥了python语言的特点了。 换作其它语言,要预做很多接口或抽象方法,在子类中实作才行吧。