15_Web框架-mini frame
1.WSGI协议概述(Python Web Server Gateway Interface)
1.WSGI允许开发者将选择web框架和web服务器分开,可以混合匹配web服务器和web框架,选择一个适合的配对
2.WSGI协议在不修改服务器和架构代码情况下确保了可以在多个架构下运行web服务器
3.Web服务器必须具备WSGI接口,所有的现代Python Web框架都已具备WSGI接口
4.WSGI接口让开发者不对代码作修改就能使服务器和特点的Web框架协同工作
5.浏览器请求WSGI_Server响应流程图: https://www.processon.com/view/link/5efcac3507912929cb6b33df
2.定义WSGI接口
def application(environ, start_response): """遵循WSGI标准的HTTP处理函数 :param environ: 一个包含所有HTTP请求信息的dict对象 :param start_response: 一个发送HTTP响应的函数 :return: 返回body信息 """ start_response('200 OK', [('Content-Type', 'text/html')]) return 'Hello World!'
3.Web服务器-WSGI协议-web框架传递的字典
{ 'HTTP_ACCEPT_LANGUAGE': 'zh-cn', 'wsgi.file_wrapper': <built-infunctionuwsgi_sendfile>, 'HTTP_UPGRADE_INSECURE_REQUESTS': '1', 'uwsgi.version': b'2.0.15', 'REMOTE_ADDR': '172.16.7.1', 'wsgi.errors': <_io.TextIOWrappername=2mode='w'encoding='UTF-8'>, 'wsgi.version': (1,0), 'REMOTE_PORT': '40432', 'REQUEST_URI': '/', 'SERVER_PORT': '8000', 'wsgi.multithread': False, 'HTTP_ACCEPT': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', 'HTTP_HOST': '172.16.7.152: 8000', 'wsgi.run_once': False, 'wsgi.input': <uwsgi._Inputobjectat0x7f7faecdc9c0>, 'SERVER_PROTOCOL': 'HTTP/1.1', 'REQUEST_METHOD': 'GET', 'HTTP_ACCEPT_ENCODING': 'gzip,deflate', 'HTTP_CONNECTION': 'keep-alive', 'uwsgi.node': b'ubuntu', 'HTTP_DNT': '1', 'UWSGI_ROUTER': 'http', 'SCRIPT_NAME': '', 'wsgi.multiprocess': False, 'QUERY_STRING': '', 'PATH_INFO': '/index.html', 'wsgi.url_scheme': 'http', 'HTTP_USER_AGENT': 'Mozilla/5.0(Macintosh;IntelMacOSX10_12_5)AppleWebKit/603.2.4(KHTML,likeGecko)Version/10.1.1Safari/603.2.4', 'SERVER_NAME': 'ubuntu' }
4.Web动态服务器-多进程
# html文件夹网盘链接: https://pan.baidu.com/s/1wbZ92KLstff3GurLV_C0lg 密码: hp9o # 下载完命令行解压后放到程序的同级路径下,解压命令: tar -zxvf 06_html.tar.gz -C ./
1.项目目录结构:
~/Desktop/Python/06_Web动态服务器 $ tree . ├── html │ ├── index.html │ ├── ... ├── web │ ├── __pycache__ │ │ └── mini_frame.cpython-37.pyc │ └── mini_frame.py └── web_server.py
2.web_server.py文件代码
import time import socket import sys import re import multiprocessing class WSGIServer(object): """定义一个WSGI服务器的类""" def __init__(self, port, documents_root): # 1. 创建套接字 self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 2.设置当服务器先close 即服务器端4次挥手之后资源能够立即释放,保证下次运行程序时可以立即绑定7890端口 self.server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # 3.绑定服务器地址 self.server_socket.bind(("", port)) # 4.变为监听套接字 self.server_socket.listen(128) # 设定资源文件的路径 self.documents_root = documents_root def set_app(self, app): """设定web框架可以调用的函数(对象)""" self.app = app def run_forever(self): """循环运行服务器,等待客户端链接并为客户端服务""" # 等待对方链接 while True: # 5.等待客户端链接 new_socket, new_addr = self.server_socket.accept() # 6.创建一个新的进程来完成这个客户端的请求任务 new_socket.settimeout(3) # 设置套接字的超时检测3s new_process = multiprocessing.Process(target=self.deal_with_request, args=(new_socket,)) new_process.start() # 因为子进程已经复制了父进程的套接字等资源,所以父进程调用close不会将他们对应的这个链接关闭的 new_socket.close() def deal_with_request(self, client_socket): """用一个新的进程以长链接的方式,为这个浏览器服务""" while True: try: # 1.接收浏览器发送过来的HTTP请求 request = client_socket.recv(1024).decode("utf-8") except Exception as ret: print("========>", ret) client_socket.close() return # 判断浏览器是否关闭 if not request: client_socket.close() return request_lines = request.splitlines() for i, line in enumerate(request_lines): print(i, line) # 提取请求的文件(index.html) # GET /a/b/c/d/e/index.html HTTP/1.1 ret = re.match(r"([^/]*)([^ ]+)", request_lines[0]) # 如果没有指定访问哪个页面,则默认访问index.html # GET / HTTP/1.1 if ret: print("正则提取数据:", ret.group(1)) print("正则提取数据:", ret.group(2)) file_name = ret.group(2) if file_name == "/": file_name = "/index.html" # 2.返回HTTP格式的数据给浏览器 # 2.1如果请求的资源不是以.py结尾,那么就是请求静态资源 if not file_name.endswith(".py"): # 读取文件数据 try: f = open(self.documents_root + file_name, "rb") except: response_body = "file not found, Please enter the correct URL." response_header = "HTTP/1.1 404 not found\r\n" response_header += "Content-Type: text/html; charset=utf-8\r\n" response_header += "Content-Length: %d\r\n" % (len(response_body)) response_header += "\r\n" response = response_header + response_body # 没有对应的响应,返回404表示没有这个页面 client_socket.send(response.encode('utf-8')) else: content = f.read() f.close() response_body = content response_header = "HTTP/1.1 200 OK\r\n" response_header += "Content-Length: %d\r\n" % (len(response_body)) response_header += "\r\n" # 将header返回给浏览器 client_socket.send(response_header.encode('utf-8') + response_body) # 2.2如果请求的资源是以.py结尾,那么就是请求动态资源 else: # 准备一个字典,里面存放需要传递给web框架的数据 env = {} # 存web返回的数据 response_body = self.app(env, self.set_response_headers) # 合并header和body response_header = "HTTP/1.1 {status}\r\n".format(status=self.headers[0]) response_header += "Content-Type: text/html; charset=utf-8\r\n" response_header += "Content-Length: %d\r\n" % len(response_body) for temp_head in self.headers[1]: response_header += "{0}:{1}\r\n".format(*temp_head) response = response_header + "\r\n" response += response_body client_socket.send(response.encode('utf-8')) def set_response_headers(self, status, headers): """此方法会在web框架中被默认调用""" # 添加服务器的一些信息 response_header_default = [ ("Data", time.ctime()), ("Server", "ItCast-python mini web server") ] # 将web框架中传递回的状态码/响应头信息存储起来 # [字符串, [xxxxx, xxx2]] self.headers = [status, response_header_default + headers] # 设置静态资源访问的路径 g_static_document_root = "./html" # 设置动态资源访问的路径 g_dynamic_document_root = "./web" def main(): """控制web服务器整体""" # python3 web_server.py 7890 mini_frame:application if len(sys.argv) == 3: try: # 获取web服务器的port port = sys.argv[1] if port.isdigit(): port = int(port) # 获取web服务器需要动态资源时,访问的web框架名字 web_frame_module_app_name = sys.argv[2] except Exception as ret: print("端口输入错误...") return else: print("运行方式如: python3 web_server.py 7890 mini_frame:application") return print("http服务器使用的port:%s" % port) # 将动态路径即存放py文件的路径,添加到path中,python解释器才可以找到路径 sys.path.append(g_dynamic_document_root) ret = re.match(r"([^:]*):(.*)", web_frame_module_app_name) if ret: # 获取模块名 web_frame_module_name = ret.group(1) # 获取可以调用web框架的应用名称 app_name = ret.group(2) # 导入web框架的主模块,返回值标记这个导入的模块 web_frame_module = __import__(web_frame_module_name) # 获取那个可以直接调用的函数(对象) app = getattr(web_frame_module, app_name) # print(app) # for test # 启动http服务器 http_server = WSGIServer(port, g_static_document_root) # 将方法封装成类的属性 http_server.set_app(app) # 运行http服务器 http_server.run_forever() if __name__ == "__main__": main()
3.mini_frame.py文件代码
import time def application(environ, start_response): """遵循WSGI标准的HTTP处理函数 :param environ: 一个包含所有HTTP请求信息的dict对象 :param start_response: 一个发送HTTP响应的函数 :return: 返回body信息 """ status = "200 OK" response_headers = [("Content-Type", "text/html")] start_response(status, response_headers) return str(environ) + "==Hello world from a simple WSGI application!--->%s\n" % time.ctime()
4.完整项目网盘链接: https://pan.baidu.com/s/1MSdjYZcxY5i8SJC5pRl0eA 密码: 0mic
5.mini-web框架
1.项目目录结构:
~/Desktop/python3/07_mini-web框架 $ tree -L 2 . ├── __init__.py ├── dynamic # 存放py模块 │ ├── __init__.py │ ├── __pycache__ │ └── mini_frame.py # mini框架 ├── log.txt # 日志 ├── readme.txt # 说明文档 ├── run.sh # shell运行脚本 ├── static │ ├── css │ └── js ├── stock_db.sql # 数据库数据准备生成脚本 ├── templates # 存放模板文件 │ ├── center.html # 个人信息界面 │ ├── index.html # 股票信息界面 │ └── update.html # 修改备注页面 ├── web_server.conf # mini web服务器配置文件 └── web_server.py # mini web服务器
2.数据库准备
-- 创建数据库 create database stock_db charset=utf8; -- 选中数据库 use stock_db; -- 导入数据,sql文件在完整项目网盘链接解压文件中 source stock_db.sql
3.web_server.py文件代码
import time import socket import sys import re import multiprocessing class WSGIServer(object): """定义一个WSGI服务器的类""" def __init__(self, port, documents_root): # 1. 创建套接字 self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 2.设置当服务器先close 即服务器端4次挥手之后资源能够立即释放,保证下次运行程序时可以立即绑定7890端口 self.server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # 3.绑定服务器地址 self.server_socket.bind(("", port)) # 4.变为监听套接字 self.server_socket.listen(128) # 设定资源文件的路径 self.documents_root = documents_root def set_app(self, app): """设定web框架可以调用的函数(对象)""" self.app = app def run_forever(self): """循环运行服务器,等待客户端链接并为客户端服务""" # 等待对方链接 while True: # 5.等待客户端链接 new_socket, new_addr = self.server_socket.accept() # 6.创建一个新的进程来完成这个客户端的请求任务 new_socket.settimeout(3) # 设置套接字的超时监测3s new_process = multiprocessing.Process(target=self.deal_with_request, args=(new_socket,)) new_process.start() # 因为子进程已经复制了父进程的套接字等资源,所以父进程调用close不会将他们对应的这个链接关闭的 new_socket.close() def deal_with_request(self, client_socket): """用一个新的进程以长链接的方式,为这个浏览器服务""" while True: try: # 1.接收浏览器发送过来的HTTP请求 request = client_socket.recv(1024).decode("utf-8") except Exception as ret: print("========>", ret) client_socket.close() return # 判断浏览器是否关闭 if not request: client_socket.close() return request_lines = request.splitlines() for i, line in enumerate(request_lines): print(i, line) # 提取请求的文件(index.html) # GET /a/b/c/d/e/index.html HTTP/1.1 ret = re.match(r"([^/]*)([^ ]+)", request_lines[0]) # 如果没有指定访问哪个页面,则默认访问index.html # GET / HTTP/1.1 if ret: print("正则提取数据:", ret.group(1)) print("正则提取数据:", ret.group(2)) file_name = ret.group(2) if file_name == "/": file_name = "/index.html" # 2.返回HTTP格式的数据给浏览器 # 2.1如果请求的资源不是以.html结尾,那么就是请求静态资源 if not file_name.endswith(".html"): # 读取文件数据 try: print(self.documents_root + file_name) f = open(self.documents_root + file_name, "rb") except: response_body = "file not found, 请输入正确的URL..." response_header = "HTTP/1.1 404 not found\r\n" response_header += "Content-Type: text/html; charset=utf-8\r\n" response_header += "Content-Length: %d\r\n" % (len(response_body.encode("utf-8"))) response_header += "\r\n" response = response_header + response_body # 没有对应的响应,返回404表示没有这个页面 client_socket.send(response.encode("utf-8")) else: content = f.read() f.close() response_body = content response_header = "HTTP/1.1 200 OK\r\n" response_header += "Content-Length: %d\r\n" % (len(response_body)) response_header += "\r\n" # 将静态请求返回给浏览器 client_socket.send(response_header.encode('utf-8') + response_body) # 2.2如果请求的资源是以.html结尾,那么就是请求动态资源 else: # 准备一个字典,里面存放需要传递给web框架的数据 env = dict() env["PATH_INFO"] = file_name # 例如 index.py # 存web返回的数据 response_body = self.app(env, self.set_response_headers) # 合并header和body response_header = "HTTP/1.1 {status}\r\n".format(status=self.headers[0]) response_header += "Content-Type: text/html; charset=utf-8\r\n" response_header += "Content-Length: %d\r\n" % len(response_body.encode("utf-8")) for temp_head in self.headers[1]: response_header += "{0}:{1}\r\n".format(*temp_head) response = response_header + "\r\n" response += response_body client_socket.send(response.encode('utf-8')) def set_response_headers(self, status, headers): """此方法会在web框架中被默认调用""" # 添加服务器的一些信息 response_header_default = [ ("Data", time.ctime()), ("Server", "ItCast-python mini web server") ] # 将web框架中传递回的状态码/响应头信息存储起来 # [字符串, [xxxxx, xxx2]] self.headers = [status, response_header_default + headers] # 设置静态资源访问的路径 # g_static_document_root = "./html" # # 设置动态资源访问的路径 # g_dynamic_document_root = "./web" def main(): """控制web服务器整体""" # python3 web_server.py 7890 mini_frame:application if len(sys.argv) == 3: try: # 获取web服务器的port port = sys.argv[1] if port.isdigit(): port = int(port) # 获取web服务器需要动态资源时,访问的web框架名字 web_frame_module_app_name = sys.argv[2] except Exception as ret: print("端口输入错误...") return else: print("运行方式如: python3 web_server.py 7890 mini_frame:application") return # 读取配置文件信息 with open("./web_server.conf") as f: conf_info = eval(f.read()) # conf_info字典里的数据为 # { # "static_path": "./static", # "dynamic_path": "./dynamic" # } print("http服务器使用的port:%s" % port) # 将动态路径即存放py文件的路径,添加到path中,python解释器才可以找到路径 sys.path.append(conf_info["dynamic_path"]) ret = re.match(r"([^:]*):(.*)", web_frame_module_app_name) if ret: # 获取模块名 web_frame_module_name = ret.group(1) # 获取可以调用web框架的应用名称 app_name = ret.group(2) # 导入web框架的主模块,返回值标记这个导入的模块 web_frame_module = __import__(web_frame_module_name) # 获取那个可以直接调用的函数(对象) app = getattr(web_frame_module, app_name) # print(app) # for test # 启动http服务器 http_server = WSGIServer(port, conf_info["static_path"]) # 将方法封装成类的属性 http_server.set_app(app) # 运行http服务器 http_server.run_forever() if __name__ == "__main__": main()
4.mini_frame.py文件代码
# import time # import os import re from urllib.parse import unquote import logging import pymysql template_root = "./templates" # 用来存放url路由映射 # url_route = { # "/index.html": index_func, # "/center.html": center_func # } g_url_route = dict() def route(url): def set_func(func): # 添加键值对,key是需要访问的url,value是当这个url需要访问的时候,需要调用的函数引用 g_url_route[url] = func def call_func(*args, **kwargs): return func(*args, **kwargs) return call_func return set_func @route(r"/index.html") def index(ret): """返回index.py需要的页面内容""" # return "hahha" + os.getcwd() # for test 路径问题 try: f = open(template_root + "/index.html") except Exception as ret: return "打开股票信息页面产生了异常: %s" % ret else: content = f.read() f.close() # --------通过数据库更新股票信息数据------- # 创建connection连接 db = pymysql.connect(host="localhost", port=3306, user="root", password="123456", database="stock_db", charset="utf8") # 获取cursor对象 cursor = db.cursor() sql = """select * from info;""" cursor.execute(sql) data_from_mysql = cursor.fetchall() cursor.close() db.close() html_template = """ <tr> <td>%d</td> <td>%s</td> <td>%s</td> <td>%s</td> <td>%s</td> <td>%s</td> <td>%s</td> <td>%s</td> <td> <input type="button" value="添加" id="toAdd" name="toAdd" systemidvaule="%s"> </td> </tr>""" html = "" for info in data_from_mysql: html += html_template % (info[0], info[1], info[2], info[3], info[4], info[5], info[6], info[7], info[1]) content = re.sub(r"\{%content%\}", html, content) return content @route(r"/center.html") def center(ret): """返回center.html需要的页面内容""" # return "hahha" + os.getcwd() # for test 路径问题 try: f = open(template_root + "/center.html") except Exception as ret: return "打开个人中心页面产生了异常: %s" % ret else: content = f.read() f.close() # --------通过数据库更新个人中心数据------- # 创建connection连接 db = pymysql.connect(host="localhost", port=3306, user="root", password="123456", database="stock_db", charset="utf8") # 获取cursor对象 cursor = db.cursor() sql = """select i.code,i.short,i.chg,i.turnover,i.price,i.highs,j.note_info from info as i inner join focus as j on i.id=j.info_id;""" cursor.execute(sql) data_from_mysql = cursor.fetchall() cursor.close() db.close() html_template = """ <tr> <td>%s</td> <td>%s</td> <td>%s</td> <td>%s</td> <td>%s</td> <td>%s</td> <td>%s</td> <td> <a type="button" class="btn btn-default btn-xs" href="/update/%s.html"> <span class="glyphicon glyphicon-star" aria-hidden="true"></span> 修改 </a> </td> <td> <input type="button" value="删除" id="toDel" name="toDel" systemidvaule="%s"> </td> </tr> """ html = "" for info in data_from_mysql: html += html_template % (info[0], info[1], info[2], info[3], info[4], info[5], info[6], info[0], info[0]) content = re.sub(r"\{%content%\}", html, content) return content # 给路由添加正则表达式的原因: 在实际开发时,url中往往会带有很多参数,例如/add/000007.html中000007就是参数 # 如果没有正则的话,那么就需要编写N次@route来进行添加url对应的函数到字典中,此时字典中的键值对有N个,浪费空间 # 而采用了正则的话,那么只要编写1次@route就可以完成多个url例如/add/00007.html /add/000036.html等对应同一个函数 @route(r"/add/(\d+)\.html") def add_focus(ret): """添加对应股票的关注""" # 1.获取股票代码 stock_code = ret.group(1) # 2.判断试下是否有这个股票代码 # 创建connection连接 db = pymysql.connect(host="localhost", port=3306, user="root", password="123456", database="stock_db", charset="utf8") cursor = db.cursor() sql = """select * from info where code=%s;""" cursor.execute(sql, (stock_code,)) # 如果要是没有这个股票代码,那么就认为是非法的请求 if not cursor.fetchone(): cursor.close() db.close() return "没有这支股票,大哥,我们是创业公司,请手下留情..." # 3.判断以下是否已经关注过 sql = """ select * from info as i inner join focus as f on i.id=f.info_id where i.code=%s;""" cursor.execute(sql, (stock_code,)) # 如果查出来了,那么表示已经关注过 if cursor.fetchone(): cursor.close() cursor.close() return "已经关注过了,请勿重复关注..." # 4.添加关注 sql = """insert into focus (info_id) select id from info where code=%s;""" cursor.execute(sql, (stock_code,)) db.commit() cursor.close() db.close() return "关注成功...." @route(r"/del/(\d+)\.html") def del_focus(ret): """取消对应股票的关注""" # 1.获取股票代码 stock_code = ret.group(1) # 2.判断试下是否有这个股票代码 db = pymysql.connect(host="localhost", port=3306, user="root", password="123456", database="stock_db", charset="utf8") cursor = db.cursor() sql = """select * from info where code=%s;""" cursor.execute(sql, (stock_code,)) # 如果要是没有这个股票代码,那么就认为是非法的请求 if not cursor.fetchone(): cursor.close() db.close() return "没有这支股票,大哥,我们是创业公司,请手下留情..." # 3. 判断以下是否已经关注过 sql = """ select * from info as i inner join focus as f on i.id=f.info_id where i.code=%s;""" cursor.execute(sql, (stock_code,)) # 如果没有关注过,那么表示非法的请求 if not cursor.fetchone(): cursor.close() db.close() return "%s之前未关注,请勿取消关注..." % stock_code # 4.取消关注 # sql = """insert into focus (info_id) select id from info where code=%s;""" sql = """delete from focus where info_id = (select id from info where code=%s);""" cursor.execute(sql, (stock_code,)) db.commit() cursor.close() db.close() return "取消关注成功...." @route(r"/update/(\d*)\.html") def update(ret): """显示更新页面的内容""" # 1.获取股票代码 stock_code = ret.group(1) # 2.打开模版 try: template_file_name = template_root + "/update.html" f = open(template_file_name) except Exception as ret: return "%s...没有找到%s" % (ret, template_file_name) else: content = f.read() f.close() # 3. 根据股票代码查询相关的备注信息 db = pymysql.connect(host="localhost", port=3306, user="root", password="123456", database="stock_db", charset="utf8") cursor = db.cursor() sql = """select f.note_info from focus as f inner join info as i on i.id=f.info_id where i.code=%s;""" cursor.execute(sql, (stock_code,)) stock_note_info = cursor.fetchone() cursor.close() db.close() content = re.sub(r"\{%code%\}", stock_code, content) content = re.sub(r"\{%note_info%\}", str(stock_note_info[0]), content) return content @route(r"/update/(\d*)/(.*)\.html") def update_note_info(ret): """进行数据的真正更新""" stock_code = ret.group(1) stock_note_info = ret.group(2) stock_note_info = unquote(stock_note_info) # 在向数据库存储时进行url解码 # 创建connection连接 db = pymysql.connect(host="localhost", port=3306, user="root", password="123456", database="stock_db", charset="utf8") # 获取cursor对象 cursor = db.cursor() sql = """update focus set note_info=%s where info_id = (select id from info where code=%s);""" cursor.execute(sql, (stock_note_info, stock_code)) db.commit() cursor.close() db.close() return "修改成功" def application(environ, start_response): """遵循WSGI标准的HTTP处理函数 :param environ: 一个包含所有HTTP请求信息的dict对象 :param start_response: 一个发送HTTP响应的函数 :return: 返回body信息 """ status = '200 OK' response_headers = [('Content-Type', 'text/html')] start_response(status, response_headers) file_name = environ['PATH_INFO'] # 添加log日志功能 logging.basicConfig(level=logging.INFO, filename='./log.txt', filemode='a', format='%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s') logging.info("访问的是: %s" % file_name) try: # return g_url_route[file_name](file_name) # 路由功能 for url, call_func in g_url_route.items(): print(url) ret = re.match(url, file_name) if ret: return call_func(ret) else: logging.warning("没有对应的函数....") return "请求的url(%s)没有对应的函数...." % file_name except Exception as ret: return "mini_frame框架产生了异常: %s" % ret
5.完整项目网盘链接: https://pan.baidu.com/s/18wkbIYlgiJntrRso6eYQZQ 密码: j94u
6.未实现的功能
1.把操作数据库的部分单独封装到一个函数中,使用时直接调用
2.配置MySQL主从服务器-从服务器查询操作,主服务器增删改操作
3.用元类实现ORM-即操作数据库部分用元类实现
6.标准库模块实现Web动态服务器
try: # Python2中的导入 from BaseHTTPServer import BaseHTTPRequestHandler from BaseHTTPServer import HTTPServer except ImportError: # Python3中的导入 from http.server import BaseHTTPRequestHandler from http.server import HTTPServer class RequestHander(BaseHTTPRequestHandler): """请求处理类""" def do_GET(self): """固定的处理GET请求方法""" # 查看请求头 print(self.headers) print("Do method get") # 组织响应行 self.send_response(200) # 组织响应头 self.send_header("Content-Type", "text/html") self.send_header("charset", "utf-8") # 响应头结束 self.end_headers() # 发送响应体 self.wfile.write(b"<h1>Hello World!</h1>") return def do_POST(self): """固定的处理POST请求方法""" pass def main(): # 指定地址 address = ("0.0.0.0", 7890) # 生成服务器对象 server = HTTPServer(address, RequestHander) # 运行 server.serve_forever() if __name__ == "__main__": main()
版权:本文版权归作者
转载:欢迎转载,但未经作者同意,必须保留此段声明;必须在文章中给出原文连接;否则必究法律责任