Web框架的本质

所有的Web应用本质上就是一个socket服务端,而用户的浏览器就是一个socket客户端
import socket

sk = socket.socket()
sk.bind(("127.0.0.1", 80))
sk.listen()


while True:
    conn, addr = sk.accept()
    data = conn.recv(8096)
    print(data)  # 将浏览器发来的消息打印出来
    conn.send(b"OK")
    conn.close()

浏览器打过来的信息为:b'GET / HTTP/1.1\r\nHost: 127.0.0.1:8520\r\nConnection: keep-alive\r\nUpgrade-Insecure-Requests: 1\r\nUser-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8\r\nAccept-Encoding: gzip, deflate, br\r\nAccept-Language: zh,en-US;q=0.9,en;q=0.8,zh-CN;q=0.7\r\n\r\n'
梳理一下:
b'GET / HTTP/1.1' \
b'Host: 127.0.0.1:8520' \
b'Connection: keep-alive' \
b'Upgrade-Insecure-Requests: 1' \
b'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36' \
b'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8' \
b'Accept-Encoding: gzip, deflate, br' \
b'Accept-Language: zh,en-US;q=0.9,en;q=0.8,zh-CN;q=0.7' \
b'' \
b''
收发的消息需要按照一定的格式来,就需要了解一下HTTP协议
半成品自定义web框架
HTTP协议对收发消息的格式要求
每个HTTP请求和响应都遵循相同的格式,一个HTTP包含Header和Body两部分,其中Body是可选的。 HTTP响应的Header中有一个 Content-Type表明响应的内容格式。
如 text/html表示HTML网页。
"""
Web框架原理:
    根据不同的URL返回不同的内容
    1. 先拿到用户访问的URL是什么
    2. 返回不同的内容
"""

import socket
sk = socket.socket()
sk.bind(('127.0.0.1', 8080))
sk.listen()


while 1:
    conn, addr = sk.accept()
    data = conn.recv(9000)
    # print(data)  # 用户发送的请求消息
    # 从请求的消息中拿到请求的URL是什么
    data_str = str(data, encoding='utf8')  # 转换成字符串类型
    # 按照\r\n分割字符串
    list1 = data_str.split('\r\n')
    url = list1[0].split()[1]
    print(url)
    if url == '/index/':
        msg = 'This is index page!'
    elif url == '/home/':
        msg = 'This is home page!'
    else:
        msg = '404 Not Found!'
    conn.send(b'HTTP/1.1 200 OK\r\n\r\n')  # 先发送响应行
    conn.send(bytes(msg, encoding='utf8'))  # 发送响应数据
    conn.close()
根据不同的url返回不同的内容
"""
Web框架原理:
    根据不同的URL返回不同的内容函数版
    1. 先拿到用户访问的URL是什么
    2. 返回不同的内容
"""

import socket
sk = socket.socket()
sk.bind(('127.0.0.1', 8080))
sk.listen()


# 定义处理用户请求的函数
def index(url):
    s = '你访问的是:{},这是我们的index页面'.format(url)
    return bytes(s, encoding='utf8')


def home(url):
    s = '你访问的主页!'
    return bytes(s, encoding='utf8')


while 1:
    conn, addr = sk.accept()
    data = conn.recv(9000)
    # print(data)  # 用户发送的请求消息
    # 从请求的消息中拿到请求的URL是什么
    data_str = str(data, encoding='utf8')  # 转换成字符串类型
    # 按照\r\n分割字符串
    list1 = data_str.split('\r\n')
    url = list1[0].split()[1]
    print(url)
    if url == '/index/':
        msg = index(url)
    elif url == '/home/':
        msg = home(url)
    else:
        msg = b'404 Not Found!'
    conn.send(b'HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=utf-8\r\n\r\n')  # 先发送响应行
    conn.send(msg)  # 发送响应数据
    conn.close()
根据不同的url返回不同的内容-函数
"""
Web框架原理:
    根据不同的URL返回不同的内容函数版
    1. 先拿到用户访问的URL是什么
    2. 返回不同的内容
"""

import socket
sk = socket.socket()
sk.bind(('127.0.0.1', 8080))
sk.listen()


# 定义处理用户请求的函数
def index(url):
    s = '你访问的是:{},这是我们的index页面'.format(url)
    return bytes(s, encoding='utf8')


def home(url):
    s = '你访问的主页!'
    return bytes(s, encoding='utf8')


def dsb(url):
    return bytes('夏雨豪是个什么人!', encoding='utf8')


# 定义一个用户访问的URL和我将要执行的函数的对应关系
url_func = [
    ('/index/', index),
    ('/home/', home),
    ('/xyh/', dsb),
]


while 1:
    conn, addr = sk.accept()
    data = conn.recv(9000)
    # print(data)  # 用户发送的请求消息
    # 从请求的消息中拿到请求的URL是什么
    data_str = str(data, encoding='utf8')  # 转换成字符串类型
    # 按照\r\n分割字符串
    list1 = data_str.split('\r\n')
    url = list1[0].split()[1]
    print(url)
    func = None
    for i in url_func:
        if i[0] == url:
            func = i[1]
            break
    if func:
        msg = func(url)
    else:
        msg = b'404 Not Found!'

    conn.send(b'HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=utf-8\r\n\r\n')  # 先发送响应行
    conn.send(msg)  # 发送响应数据
    conn.close()
根据不同的URL返回不同的内容函数进阶版
"""
Web框架原理:
    返回具体的HTML页面
"""

import socket
sk = socket.socket()
sk.bind(('127.0.0.1', 8080))
sk.listen()


# 定义处理用户请求的函数
def index(url):
    s = '你访问的是:{},这是我们的index页面'.format(url)
    return bytes(s, encoding='utf8')


def home(url):
    s = '你访问的主页!'
    return bytes(s, encoding='utf8')


def dsb(url):
    return bytes('小明是个什么人!', encoding='utf8')


def login(url):
    # 返回login.html
    with open('login.html', 'rb') as f:
        return f.read()


# 定义一个用户访问的URL和我将要执行的函数的对应关系
url_func = [
    ('/index/', index),
    ('/home/', home),
    ('/xyh/', dsb),
    ('/login/', login),
]


while 1:
    conn, addr = sk.accept()
    data = conn.recv(9000)
    # print(data)  # 用户发送的请求消息
    # 从请求的消息中拿到请求的URL是什么
    data_str = str(data, encoding='utf8')  # 转换成字符串类型
    # 按照\r\n分割字符串
    list1 = data_str.split('\r\n')
    url = list1[0].split()[1]
    print(url)
    func = None
    for i in url_func:
        if i[0] == url:
            func = i[1]
            break
    if func:
        msg = func(url)
    else:
        msg = b'404 Not Found!'

    conn.send(b'HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=utf-8\r\n\r\n')  # 先发送响应行
    conn.send(msg)  # 发送响应数据
    conn.close()
返回具体的HTML页面
"""
Web框架原理:
    返回具体的HTML页面
"""
import time
import socket
sk = socket.socket()
sk.bind(('127.0.0.1', 8080))
sk.listen()


# 定义处理用户请求的函数
def index(url):
    with open('index.html', 'r', encoding='utf8') as f1:
        html_s = f1.read()
    # 根据用户不同,取出不同的数据
    # 用不同的数据去替换页面上的特殊符号
    now = str(time.time())
    msg = html_s.replace('@@xx@@', now)
    return bytes(msg, encoding='utf8')


def home(url):
    s = '你访问的主页!'
    return bytes(s, encoding='utf8')


def dsb(url):
    return bytes('小明是个什么人!', encoding='utf8')


def login(url):
    # 返回login.html
    with open('login.html', 'rb') as f:
        return f.read()


# 定义一个用户访问的URL和我将要执行的函数的对应关系
url_func = [
    ('/index/', index),
    ('/home/', home),
    ('/xyh/', dsb),
    ('/login/', login),
]


while 1:
    conn, addr = sk.accept()
    data = conn.recv(9000)
    # print(data)  # 用户发送的请求消息
    # 从请求的消息中拿到请求的URL是什么
    data_str = str(data, encoding='utf8')  # 转换成字符串类型
    # 按照\r\n分割字符串
    list1 = data_str.split('\r\n')
    url = list1[0].split()[1]
    print(url)
    func = None
    for i in url_func:
        if i[0] == url:
            func = i[1]
            break
    if func:
        msg = func(url)
    else:
        msg = b'404 Not Found!'

    conn.send(b'HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=utf-8\r\n\r\n')  # 先发送响应行
    conn.send(msg)  # 发送响应数据
    conn.close()
返回动态网页内容
"""
Web框架原理:
    返回具体的HTML页面
"""
import time
from wsgiref.simple_server import make_server


# 定义处理用户请求的函数
def index(url):
    with open('index.html', 'r', encoding='utf8') as f1:
        html_s = f1.read()
    # 根据用户不同,取出不同的数据
    # 用不同的数据去替换页面上的特殊符号
    now = str(time.time())
    msg = html_s.replace('@@xx@@', now)
    return bytes(msg, encoding='utf8')


def home(url):
    s = '你访问的主页!'
    return bytes(s, encoding='utf8')


def dsb(url):
    return bytes('小明是个什么人!', encoding='utf8')


def login(url):
    # 返回login.html
    with open('login.html', 'rb') as f:
        return f.read()


# 定义一个用户访问的URL和我将要执行的函数的对应关系
url_func = [
    ('/index/', index),
    ('/home/', home),
    ('/xyh/', dsb),
    ('/login/', login),
]


# wsgiref模块的格式要求
def run_server(environ, start_response):
    start_response('200 OK', [('Content-Type', 'text/html;charset=utf8'), ])  # 设置HTTP响应的状态码和头信息
    url = environ['PATH_INFO']  # 取到用户输入的url
    func = None
    for i in url_func:
        if i[0] == url:
            func = i[1]
            break
    if func:
        msg = func(url)
    else:
        msg = b'404 Not Found!'
    return [msg, ]


if __name__ == '__main__':
    httpd = make_server('127.0.0.1', 8080, run_server)
    print("我在8080等你哦...")
    httpd.serve_forever()
wsfiref版web开发
"""
Web框架原理:
    返回具体的HTML页面
"""
import time
from wsgiref.simple_server import make_server


# 定义处理用户请求的函数
def index(url):
    with open('index.html', 'r', encoding='utf8') as f1:
        html_s = f1.read()
    # 根据用户不同,取出不同的数据
    # 用不同的数据去替换页面上的特殊符号
    now = str(time.time())
    msg = html_s.replace('@@xx@@', now)
    return bytes(msg, encoding='utf8')


def home(url):
    s = '你访问的主页!'
    return bytes(s, encoding='utf8')


def dsb(url):
    return bytes('小明是个什么人!', encoding='utf8')


def login(url):
    # 返回login.html
    with open('login.html', 'rb') as f:
        return f.read()


# 定义一个用户访问的URL和我将要执行的函数的对应关系
url_func = [
    ('/index/', index),
    ('/home/', home),
    ('/xyh/', dsb),
    ('/login/', login),
]


# wsgiref模块的格式要求
def run_server(environ, start_response):
    start_response('200 OK', [('Content-Type', 'text/html;charset=utf8'), ])  # 设置HTTP响应的状态码和头信息
    url = environ['PATH_INFO']  # 取到用户输入的url
    func = None
    for i in url_func:
        if i[0] == url:
            func = i[1]
            break
    if func:
        msg = func(url)
    else:
        msg = b'404 Not Found!'
    return [msg, ]


if __name__ == '__main__':
    httpd = make_server('127.0.0.1', 8080, run_server)
    print("我在8080等你哦...")
    httpd.serve_forever()
wsgiref+jinja版
对于真实开发中的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模块来替换我们自己写的web框架的socket server。
模板的原理就是字符串替换,我们只要在HTML页面中遵循jinja2的语法规则写上,其内部就会按照指定的语法进行相应的替换,从而达到动态的返回内容。
Python中Web框架的分类
    收发socket消息
    根据不同的URL执行不同的函数(业务逻辑)
    字符串替换(动态网页)
        
第一种分类:(按照上面的三部分功能划分)
     自己实现b和c,使用第三方的a      --> Django
     自己实现b,使用第三方的a和c      --> Flask
     自己实现a、b、c                 --> Tornado
第二种分类:
     Django(大而全)
     其他
Django
安装
    命令行安装:
        pip install django==1.11.16
    补充:
        pip install django==1.11.16 -i                 
        https://pypi.tuna.tsinghua.edu.cn/simple some-package
        pip list
    PyCharm安装
创建我们第一个Django项目
命令行创建
    django-admin startproject 项目名
PyCharm创建
    File -> new project -> 左边选第二项,右边填项目名并且选择Python解释器
运行Django项目
    命令行
        切换到项目的目录下
            python manage.py runserver
            python manage.py runserver 127.0.0.1:8080
            python manage.py runserver 8090
    PyCharm
        点绿色的三角(注意左侧名称要与项目名相同)
TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, "template")],  # template文件夹位置
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]
<!--用来存放HTML页面-->
模板的文件配置
STATIC_URL = '/static/'  # HTML中使用的静态文件夹前缀
STATICFILES_DIRS = [
    os.path.join(BASE_DIR, "static"),  # 静态文件存放位置
]
css,js样式等
静态文件配置
HttpResponse
内部传入一个字符串参数,返回给浏览器。
def index(request):
    # 业务逻辑代码
    return HttpResponse("OK")
render
找到那个html文件  读取文件内容  按照HTTP协议的格式返回
redirect
接受一个URL参数,表示跳转到指定的URL。
def index(request):
    # 业务逻辑代码
    return redirect("/home/")

 

 

posted @ 2018-10-24 15:28  .why  阅读(512)  评论(0)    收藏  举报
Live2D