WSGI
WSGI(Web Server Gateway Interface)web服务器网关接口。它是python下的一个标准,定义了web服务器和web应用或框架之间一种简单而通用的接口。在python中,它的具体实现是wsgiref模块。客户端(浏览器)把http请求发送给web服务器,web服务器封装请求,再把请求发送给web应用,web应用处理请求,通过web服务器,将响应返回给客户端。
手动实现一个web框架
为了更好的理解web框架,我们来试着手动实现一个简单的web框架。先写基本的逻辑:
from wsgiref.simple_server import make_server # 引用类
route = {} # 用来存储url path 和函数的对应关系的路由
def deco(name): # 装饰器,自动添加视图函数到路由
def wrapper(func):
route[name] = func
return wrapper
@deco('/login')
def login(request):
with open('login.html', 'rb')as f:
return [f.read()]
@deco('/auth')
def auth(request):
# environ对象的QUERY_STRING键对应用户提交的用户名和密码,我们将它提取出来。
login_info = request.get('QUERY_STRING') # user=ayhan&pwd=123
user, pwd = login_info.split('&')
_, user = user.split('=')
_, pwd = pwd.split('=')
if user == 'ayhan' and pwd == '123':
return [b'login ok!']
else:
return [b'user or password error']
def application(environ, start_response):
start_response('200 OK', [('Content-Type', 'text/html')])
# environ ; 由wsgiref封装了请求信息的对象。
# start_response响应头:状态码 + 键值对
# 最简单的响应如下,直接返回一个bytes字符串
# msg = '<h1>hello world</h1>'
# return [msg.encode('utf-8')] # 注意,要加[]
# 实际中应该根据用户的请求,返回不同的响应
path = environ.get('PATH_INFO')
# 获取请求路径,通过它来判断用户访问的路径,来返回不同的页面
# if path == '/seb':
# with open('seb.html','rb')as f:
# data = f.read()
# return [data]
# elif path == '/tom':
# pass
# else:
# return [b'404']
# 不用if判断,用路由来处理请求,调用对应的视图函数
if path in route: # 路由分发
res = route[path](environ)
return res
else:
return [b'404']
server = make_server("", 8080, application) # 实例化一个WSGI服务器对象(底层基于socket),监听ip和端口
# 不写默认本机ip; 重写application方法
server.serve_forever() # 运行服务器,调用application
将上述代码用包和模块的方式组织起来,就是一个简单的框架:
程序主逻辑 bin.py
如下:
from wsgiref.simple_server import make_server # 引用类
from views import *
def application(environ, start_response):
start_response('200 OK', [('Content-Type', 'text/html')])
path = environ.get('PATH_INFO')
if path in route: # 路由分发
res = route[path](environ)
return res
else:
return [b'404']
if __name__ == '__main__':
server = make_server("", 8080, application)
视图函数如下:
route = {} # 用来存储url path 和函数的对应关系的路由
def deco(name): # 装饰器,自动添加视图函数到路由
def wrapper(func):
route[name] = func
return wrapper
@deco('/login')
def login(request):
with open('templates/login.html', 'rb')as f:
return [f.read()]
@deco('/auth')
def auth(request):
# environ对象的QUERY_STRING键对应用户提交的用户名和密码,我们将它提取出来。
login_info = request.get('QUERY_STRING') # user=ayhan&pwd=123
user, pwd = login_info.split('&')
_, user = user.split('=')
_, pwd = pwd.split('=')
if user == 'ayhan' and pwd == '123':
return [b'login ok!']
else:
return [b'user or password error']
这样,一个简单的web框架就完成了,只需添加视图函数和模板,就可以可扩展其功能。
初识Django
Django是用python开发的一个开源web框架。有了它,我们可以专注于编写清晰、易维护的代码。
1 创建项目
在终端输入如下命令,可以创建一个项目:
django-admin startproject project_name
,项目名可以自定义,这里我们创建一个名为myweb的项目,创建完成后,可以看到如下的目录结构:
项目名根目录下分别有manage.py和一个全局文件夹myweb:
- manage.py 命令行工具,用来与Django进行交互
- __init__.py python包文件
- settings.py 配置文件
- urls.py 路由分发,定义了url访问路径与视图函数的映射关系
- wsgi.py 网关文件,部署服务器用
Django内建了一个轻量级web服务器,仅供开发使用。它同一时间只能处理一次请求,且没有安全审计。因此在生成环境中,还是要部署Apache或Nginx这类专业的web服务器。
现在我们在终端通过命令来启动这个开发服务器:
python manage.py runserver [ip] [port]
如果不指定ip和端口,默认运行在本机的8000端口。通过浏览器访问http://127.0.0.1:8000/时,将看到一个默认页面。那是因为我们还没有创建任何应用并设置路由。下面我们就为这个项目创建一个应用。
2 创建应用
切换到到项目的根目录下,输入如下命令:
python manage.py startapp app_name
这里,我创建一个名为blog的应用。项目根目录下将生成一个以blog命名的新目录。我们在该目录下手动新建一个templates文件夹,用来存放html模板。
打开全局文件夹myweb下的setting.py,将新创建的blog应用添加到INSTALLED_APPS中。Django在寻找应用模板,及执行数据库迁移等操作,都要以这步为前提:
3 定义视图函数
views.py中的定义的函数是实现应用的具体业务逻辑,这些函数统称为视图函数。现在我们来定义一个视图函数,用它来返回首页内容。并在template文件夹下建立一个index.html文件,编辑内容<h1>Welcome to index page!</h1>
。
from django.shortcuts import render
def index(request):
"""
该视图函数用来返回首页的内容
:param request: 请求对象
:return: 返回由render函数渲染的html模板并返回的http响应
"""
return render(request, 'index.html')
4 url映射
我们知道用户通过url访问网站,不同的url应该调用不同的视图函数,这样才能正确处理用户的请求,并返回响应内容。现在我们为刚刚定义的index视图函数添加url映射关系。
修改myweb文件夹下的urls.py文件,添加url与映射。
from django.conf.urls import url
from django.contrib import admin
from blog import views as blog_views
# 从blog应用中导入视图函数
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^index/$', blog_views.index),
# 添加映射,当用户的url路径是index/时,调用blog应用中的index视图函数
]
这里简单说下一个url的构成:
5 启动服务
python manage.py runserver [ip] [port]
比如:python manage.py runserver 192.168.16.2:8000
。注意访问时可能会提示DisallowedHost,解决方案:编辑项目settings.py 中的ALLOWED_HOSTS = ['*']
即可。
我们在创建项目时已经启动了服务,Django会检测代码更改并自动重启服务。如果有必要,可以ctl + c
退出,然后重启服务。现在我们试着访问http://127.0.0.1/index
,将看到首页: