web框架的本质

2018-11-02  本文已影响0人  莫辜负自己的一世韶光

所有的web应用本质上就是一个socket服务端,而用户的浏览器就是一个socket客户端,这样我们就可以实现一个web框架了.

用户的浏览器一输入网址,会给服务端发送数据,那浏览器会发送什么数据?怎么发?这个谁来定? 你这个网站是这个规定,他那个网站按照他那个规定,这互联网还能玩么?

所以,必须有一个统一的规则,让大家发送消息、接收消息的时候有个格式依据,不能随便写。

这个规则就是HTTP协议,以后浏览器发送请求信息也好,服务器回复响应信息也罢,都要按照这个规则来。

HTTP协议主要规定了客户端和服务器之间的通信格式,那HTTP协议是怎么规定消息格式的呢?

让我们首先打印下我们在服务端接收到的消息是什么。

这样访问网页的时候,会出现如下界面:

这是因为响应的时候,必须按照一定的格式才可以.


这样并不能很好的响应不同的请求,可以根据解析请求的内容,根据请求不同的URL,返回不同的内容.


# encoding:utf-8
__author__ = 'Fioman'
__date__ = '2018/11/2 17:08'
import socket

sock = socket.socket()
sock.bind(('127.0.0.1', 8000))
sock.listen()


def index(url):
    s = "这是{}页面!".format(url)
    return bytes(s, encoding='utf-8')


def home(url):
    s = "这是{}页面!".format(url)
    return bytes(s, encoding='utf-8')


func_urls = [
    ('/index/', index),
    ('/home/', home),
]
while True:
    conn, addr = sock.accept()
    data = conn.recv(8096)
    data = str(data, encoding='utf-8')
    requestLine = data.split('\r\n')[0]
    url = requestLine.split(' ')[1]

    # 路径和函数的对应关系
    func = None
    for i in func_urls:
        if i[0] == url:
            func = i[1]
            break

    if func:
        response = func(url)
    else:
        response = b'404 not found!'
    conn.send(b'HTTP/1.1 200 OK')
    conn.send(response)

    conn.close()

sock.close()


本质就是读取本地的HTML文件,然后以二进制数据的形式发送给客户端

# encoding:utf-8
__author__ = 'Fioman'
__date__ = '2018/11/2 17:08'
import socket

sock = socket.socket()
sock.bind(('127.0.0.1', 8000))
sock.listen()


def index(url):
    with open('index.html', 'rb', encoding='utf-8') as f:
        ret = f.read()
    return ret


def home(url):
    with open('home.html', 'rb', encoding='utf-8') as f:
        ret = f.read()
    return ret


func_urls = [
    ('/index/', index),
    ('/home/', home),
]
while True:
    conn, addr = sock.accept()
    data = conn.recv(8096)
    data = str(data, encoding='utf-8')
    requestLine = data.split('\r\n')[0]
    url = requestLine.split(' ')[1]

    # 路径和函数的对应关系
    func = None
    for i in func_urls:
        if i[0] == url:
            func = i[1]
            break

    if func:
        response = func(url)
    else:
        response = b'404 not found!'
    conn.send(b'HTTP/1.1 200 OK')
    conn.send(response)

    conn.close()

sock.close()


动态网页的实现,无非就是字符串的替换

对于真实开发中的python web程序来说,一般会分为两部分:服务器程序和应用程序。

服务器程序负责对socket服务器进行封装,并在请求到来时,对请求的各种数据进行整理。

应用程序则负责具体的逻辑处理。为了方便应用程序的开发,就出现了众多的Web框架,例如:Django、Flask、web.py 等。不同的框架有不同的开发方式,但是无论如何,开发出的应用程序都要和服务器程序配合,才能为用户提供服务。

这样,服务器程序就需要为不同的框架提供不同的支持。这样混乱的局面无论对于服务器还是框架,都是不好的。对服务器来说,需要支持各种不同框架,对框架来说,只有支持它的服务器才能被开发出的应用使用。

这时候,标准化就变得尤为重要。我们可以设立一个标准,只要服务器程序支持这个标准,框架也支持这个标准,那么他们就可以配合使用。一旦标准确定,双方各自实现。这样,服务器可以支持更多支持标准的框架,框架也可以使用更多支持标准的服务器。

WSGI(Web Server Gateway Interface)就是一种规范,它定义了使用Python编写的web应用程序与web服务器程序之间的接口格式,实现web应用程序与web服务器程序间的解耦。

常用的WSGI服务器有uwsgi、Gunicorn。而Python标准库提供的独立WSGI服务器叫wsgiref,Django开发环境用的就是这个模块来做服务器。

wsgiref

我们利用wsgiref模块来替换我们自己写的web框架的socket server部分

# encoding:utf-8
__author__ = 'Fioman'
__date__ = '2018/11/2 17:35'
import time
from wsgiref.simple_server import make_server


# 将返回不同的内容部分封装为函数
def index(url):
    with open('index.html', 'r', encoding='utf-8') as f:
        s = f.read()
        now = str(time.time())
        s = s.replace("@@xx@@", now)
    return bytes(s, encoding='utf-8')


def home(url):
    with open('home.html', 'rb', encoding='utf-8') as f:
        ret = f.read()
    return ret


# 定义一个url和实际要执行的函数的对应关系
func_urls = [
    ('/index/', index),
    ('/home/', home),
]


def run_server(environ, start_response):
    # 设置HTTP响应的状态码和头消息
    start_response('200 OK', [('Content-Type', 'text/html;charset=utf8'), ])
    # 取到用户输入的url
    url = environ['PATH_INFO']
    func = None

    for i in func_urls:
        if i[0] == url:
            func = i[1]
            break

    if func:
        response = func(url)
    else:
        response = b'404 not found'

    return [response,]



if __name__ == '__main__':
    httpd = make_server('127.0.0.1', 8000, run_server)
    print('我在8000端口等你哦.........')
    # 启动服务
    httpd.serve_forever()

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
    <h1>{{name}}</h1>

    <ul>
        {% for item in user_list %}
        <li>{{item}}</li>
        {% endfor %}
    </ul>

</body>
</html>
# encoding:utf-8
__author__ = 'Fioman'
__date__ = '2018/11/2 18:59'

from wsgiref.simple_server import make_server
from jinja2 import Template


def index():
    with open('index.html')
        ret = f.read()
        template = Template(ret)
        data = template.render(name='John Doe', user_list=['alex', 'eric'])

        return data.encode('utf-8')


def login():
    f = open('login.html')
    data = f.read()

    return data


def routers():
    urlpatterns = (
        ('/index/', index),
        ('/login/', login),
    )

    return urlpatterns


def run_server(environ, start_response):
    start_response('200 OK', [('Content-Type', 'text/html')])
    url = environ['PATH_INFO']
    urlpatterns = routers()

    func = None
    for item in urlpatterns:
        if item[0] == url:
            func = item[1]
            break

    if func:
        return func()
    else:
        return '404 not found'


if __name__ == '__main__':
    httpd = make_server('127.0.0.1', 8000, run_server)
    print("Serving HTTP on port 8000....")
    httpd.serve_forever()

总结一下

web框架的本质

socket服务端 和 浏览器客户端的通信

socket服务端功能划分:

Web框架的分类

上一篇下一篇

猜你喜欢

热点阅读