web学习之wsgi

from wsgiref.simple_server import make_server


def application(environ, start_response):
    start_response('200 OK', [('Content-Type', 'text/html')])
    return [b'<h1>Hello, web!</h1>']


httpd = make_server('', 8080, application)

print('Serving HTTP on port 8000...')
# 开始监听HTTP请求:
httpd.serve_forever()
View Code

          学习笔记之WSGI

WSGI是干嘛用的?为什么存在?

因为我们不希望接触到TCP连接、HTTP原始请求和响应格式,所以,需要一个统一的接口,让我们专心用Python编写Web业务。

而这个接口就算WSGI:Web Server Gateway Interface。

make_server的作用是帮我们封装一些操作:
包括socket对象,绑定(bind),监听(listen)等。

即是将如下这些封装打包:

sk = socket.socket()
 
address = ('127.0.0.1', 8000)
sk.bind(address)
sk.listen(3)

这样子我们就省了一些功夫去做这些基础性的工作,但是make_server还是需要ip地址和端口来绑定对象。

传入的applicadtion参数不需要自己执行,传进去的是函数名,在内部会帮你执行。
之后拿到一个make_server实例化对象传给httpd,再用serve_forever去执行。

application的重要参数:
(注意:application是server端,所设置的响应头和响应体都是给客户端看的。)

  • .start_response: 设置响应头的参数

  例如:
  start_response('200 OK', [('Content-Type', 'text/html')])
  其字典类型的参数应该放在一个大列表里面,大列表里包括键值对元祖。
  例如('Content-Type', 'text/html')就相当于传了 Content-Type = text / html 给客户端

  • environ:封装http解析的信息的参数。

http解析完的数据都放到了environ这个对象里面
想取出environ的值可以通过取出键的值,例如你的子路径是book时可以
用environ['PATH_INFO']。当你相对客户输入不同的路径做出不同的响应时,
可也通过if else语句和environ结合来做。

def application(environ, start_response):
               start_response('200 OK', [('Content-Type', 'text/html')])
               path = environ['PATH_INFO']
               if path == '/book':
                    return [b'Hello book']
               elif path == '/blog':
                    return [b'Hello web']
               else:
                    return ['<h1>404</h1>'.encode('utf8')]
View Code

优化一下:将客户端发送不同的请求时返回的不同的数据这步操作分别写到不同的函数里边。

def f1():
                return [b'Hello book']
           def f2():
                return [b'Hello web']
           def application(environ, start_response):
               start_response('200 OK', [('Content-Type', 'text/html')])
               path = environ['PATH_INFO']
               if path == '/book':
                    return f1()
               elif path == '/blog':
                    return f2()
               else:
                    return ['<h1>404</h1>'.encode('utf8')]
View Code

我们也可以传入environ参数给f1()和f2(),这样这两个函数就可以利用environ里面的包装的信息了。

由于子路径有多种,用if else效率并不高,因此我们可以用循环遍历来优化

代码如下:

def routers():

            urlpatterns = (
                ('/book',f1),
                ('/web',f2),
            )
            return urlpatterns


        def application(environ, start_response):

            print(environ['PATH_INFO'])
            path=environ['PATH_INFO']
            start_response('200 OK', [('Content-Type', 'text/html')])


            urlpatterns = routers()
            func = None
            for item in urlpatterns:
                if item[0] == path:
                    func = item[1]
                    break
            if func:
                return func(environ)
            else:
                return ["<h1>404</h1>".encode("utf8")]
View Code

过程:将子路径和所对应的函数都给封装到一个元祖里面,然后将这些元祖封装到另一个元祖里面
   给urlpaytterns。将这些信息整合在routers函数里面,在application函数里面用for循环遍历
      routers函数返回的信息,当item[0]跟客户端(浏览器)输入的一致时,就可以调用item[1]传递
   给fun,然后break跳出循环接着执行下面的代码,否则继续循环遍历。

优点:1.添加新的子路径时不用继续死套if else语句,起了简化作用。
      2.返回数据变活了

优化完源码

from wsgiref.simple_server import make_server


def f1(environ):
    return [b'Hello book']
def f2(environ):
    return [b'Hello web']

def routers():
    urlpatterns = (
        ('/book', f1),
        ('/web', f2),
    )
    return urlpatterns


def application(environ, start_response):
    # 通过environ封装成一个所有请求信息的对象
    # start_response可以很方便的设置响应头
    print(environ['PATH_INFO'])
    path = environ['PATH_INFO']
    start_response('200 OK', [('Content-Type', 'text/html')])

    urlpatterns = routers()
    func = None
    for item in urlpatterns:
        if item[0] == path:
            func = item[1]
            break
    if func:
        return func(environ)
    else:
        return ["<h1>404</h1>".encode("utf8")]

#封装socket对象以及准备过程(socket,bind,listen)
httpd = make_server('', 8000, application)

print('Serving HTTP on port 8000...')
# 开始监听HTTP请求:
httpd.serve_forever()
View Code

现在,我们完成一个在浏览器页面显示时间的小作业,需求:当我们在浏览器端输入127.0.0.1:xxxx/

current_time时,在浏览器页面打印出当前时间。

  • xxxx表示当前运行的端口号

 


 

作业答案区:

先建立一个HTML文件,内容如下:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<h1>current_time:  !cur_time!</h1>

</body>
</html>
View Code
接着在后端接受前端文件,对其进行修改返回给浏览器即可。代码如下:

from wsgiref.simple_server import make_server
import time

def routers():

    urlpatterns = (
        ('/current_time',current_time),
    )
    return urlpatterns

def current_time(request):


    cur_time = time.ctime(time.time())  # ctime里面传一个时间戳 而time.time()就算时间戳
    f = open('current_time.html','rb')
    data = f.read()

    data = str(data,'utf8').replace('!cur_time!',str(cur_time))

    return [data.encode('utf8')]


def application(environ, start_response):

    print(environ['PATH_INFO'])
    path=environ['PATH_INFO']
    start_response('200 OK', [('Content-Type', 'text/html')])


    urlpatterns = routers()
    func = None
    for item in urlpatterns:
        if item[0] == path:
            func = item[1]
            break
    if func:
        return func(environ)
    else:
        return ["<h1>404</h1>".encode("utf8")]

httpd = make_server('', 8084, application)

print('Serving HTTP on port 8084...')

# 开始监听HTTP请求:

httpd.serve_forever()
View Code

 

这是第一次写博客记录学习~   多谢支持~~

 

 

 

posted @ 2019-01-30 10:44  Cai先生  Views(241)  Comments(0)    收藏  举报