[] Django Web framework nature --2019-08-17 05:43:11

Original: http://blog.gqylpy.com/gqy/258

"@
*
We can interpret it this way: All == Web applications is essentially a socket server ==, and the user's browser is a socket == customer service == ** end.

So that we can implement their own Web framework of:

from socket import *

sk = socket(AF_INET, SOCK_STREAM)
sk.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
sk.bind(('127.0.0.1', 8080))
sk.listen()

while True:
    conn, addr = sk.accept()
    data = conn.recv(9000)
    conn.send(b'HTTP/1.1 200 OK\r\n\r\n')       # 响应状态行
    conn.send(b'Hello,world!')
    conn.close()

It can be said on the Web service extensions are essentially out of this dozen lines of code base, this code is their fathers.

A user's browser, enter the URL, the server will send data that the browser will send what data? How hair? Who fixed this? You website is this provision, according to his Web site that he that provision, which the Internet can play it?
Therefore, there must be a uniform rule, so that we send messages, receive messages when there is a format basis, not just to write.
This rule is the HTTP protocol, the browser sends a request message after Ye Hao, the server replies response information worth mentioning, should follow this rule.
The main provisions of the HTTP protocol communication format between the client and server, HTTP protocol that is how the message format prescribed it?

Let us first print what messages we received in service termination are:

from socket import *

sk = socket(AF_INET, SOCK_STREAM)
sk.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
sk.bind(('127.0.0.1', 8080))
sk.listen()

while True:
    conn, addr = sk.accept()
    data = conn.recv(9000)
    print(data)  # 将浏览器发来的消息打印出来
    conn.send(b'HTTP/1.1 200 OK\r\n\r\n')
    conn.send(b'Hello,world!')
    conn.close()

Output is as follows:

b'GET / HTTP/1.1\r\nHost: 127.0.0.1:8080\r\nConnection: keep-alive\r\nPragma: no-cache\r\nCache-Control: no-cache\r\nUpgrade-Insecure-Requests: 1\r\nUser-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 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-CN,zh;q=0.9,en;q=0.8\r\n\r\n'

Then we will see a response to the information we access the blog official web browser of what is received, information about the response can be seen in the network browser tab Debug window:
Here Insert Picture Description
We need to find messages sent and received in accordance with a certain format, here it is necessary to know the HTTP protocol.

Each HTTP requests and responses follow the same format, an HTTP Header and Body comprising two portions, wherein Body is optional. Header HTTP response has a == Content-Type == show content format of the response. As == text / html == represent HTML page.

HTTP GET request format:
Here Insert Picture Description

HTTP response format:
Here Insert Picture Description
****

Return different content depending on the path

regular version

== idea: to get the route request URL from which the request data, and make a judgment == take the path.

from socket import *

sk = socket(AF_INET, SOCK_STREAM)
sk.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
sk.bind(('127.0.0.1', 8080))
sk.listen()

while True:
    conn, addr = sk.accept()
    data = conn.recv(8096)
    # 把收到的字节类型的数据转换成字符串
    data_str = str(data, encoding='UTF-8')
    first_line = data_str.split('\r\n')[0]  # 按\r\n分隔
    url = first_line.split()[1]  # 在按空格切割
    conn.send(b'HTTP/1.1 200 OK\r\n\r\n')  # 响应状态行

    if url == '/index':
        response = 'index'
    elif url == '/home':
        response = 'home'
    else:
        response = '404 not found!'

    conn.send(bytes(response, encoding='UTF-8'))
    conn.close()

上面的代码解决了对于不同URL路径返回不同内容的需求。
但是问题又来了,如果有很多的路径要判断怎么办呢?难道要挨个写if判断?
答案是否定的,我们有更聪明的办法:

函数版

from socket import *

sk = socket(AF_INET, SOCK_STREAM)
sk.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
sk.bind(('127.0.0.1', 8080))
sk.listen()


# 将返回不同的内容部分封装成函数
def index(url):
    s = "这是%s页面!" % url
    return bytes(s, encoding='UTF-8')


def home(url):
    s = "这是%s页面!" % url
    return bytes(s, encoding='UTF-8')


while True:
    conn, addr = sk.accept()
    data = conn.recv(8096)
    # 把收到的字节类型的数据转换成字符串
    data_str = str(data, encoding='UTF-8')
    first_line = data_str.split('\r\n')[0]  # 按\r\n分隔
    url = first_line.split()[1]  # 在按空格切割
    conn.send(b'HTTP/1.1 200 OK\r\n\r\n')  # 响应状态行

    if url == '/index':
        response = index(url)
    elif url == '/home':
        response = home(url)
    else:
        response = b'404 not found!'

    conn.send(response)
    conn.close()

看起来上面的代码还是要挨个写if判断,怎么办?
只要思想不滑坡,方法总比问题多,走着!

函数进阶版

from socket import *

sk = socket(AF_INET, SOCK_STREAM)
sk.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
sk.bind(('127.0.0.1', 8080))
sk.listen()


# 将返回不同的内容部分封装成函数
def index(url):
    s = "这是%s页面!" % url
    return bytes(s, encoding='UTF-8')


def home(url):
    s = "这是%s页面!" % url
    return bytes(s, encoding='UTF-8')


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

while True:
    conn, addr = sk.accept()
    data = conn.recv(8096)
    # 把收到的字节类型的数据转换成字符串
    data_str = ?tr(data, encoding='UTF-8')
    first_line = data_str.split('\r\n')[0]  # 按\r\n分隔
    url = first_line.split()[1]  # 在按空格切割
    conn.send(b'HTTP/1.1 200 OK\r\n\r\n')  # 响应状态行


    # -------关键就在于这一坨代码-------
    func = None
    for i in url_list:
        if url == i[0]:
            func = i[1]
            break
    response = func(url) if func else b'404 not found!'


    conn.send(response)
    conn.close()

完美解决了不同URL返回不同内容的问题。
但是我们不仅仅是想返回几个字符串,我们想给浏览器返回完整的HTML内容,这又该怎么办呢?接着走!
***

返回具体的HTML文件

首先我们要知道:==不管是什么内容,最后都是转换成字节数据发送出去的.==
那么,我们可以以二进制形式打开HTML文件,读取文件的数据,然后再发送给浏览器.

from socket import *

sk = socket(AF_INET, SOCK_STREAM)
sk.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
sk.bind(('127.0.0.1', 8080))
sk.listen()


# 将返回不同的内容部分封装成函数
def index(url):
    with open('index.html', 'rb') as f: return f.read()


def home(url):
    with open('home.html', 'rb') as f: return f.read()


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

while True:
    # ------------ 建立连接 接收消息 ------------
    conn, addr = sk.accept()
    data = conn.recv(8096)

    # ------------ 对客服端发来的消息做处理 ------------
    # 把收到的字节类型的数据转换成字符串
    data_str = str(data, encoding='UTF-8')
    first_line = data_str.split('\r\n')[0]  # 按\r\n分隔
    url = first_line.split()[1]  # 在按空格切割

    # ------------ 业务逻辑处理部分 ------------
    func = None
    for i in url_list:
        if url == i[0]:
            func = i[1]
            break
    response = func(url) if func else b'404 not found!'

    # ----------- 回复响应消息 -----------
    conn.send(b'HTTP/1.1 200 OK\r\n\r\n')  # 响应状态行
    conn.send(response)
    conn.close()

没错,还有问题!
这网页是能够显示出来了,但都是静态的啊,页面的内容不会变化,我们想要的是动态网站!
***

让网页动态起来

==思路:使用字符串替换功能来实现这个需求.==
这里我们是使用当前时间来模拟动态的数据

login函数对应文件:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta http-equiv="content-Type" charset="UTF-8">
    <meta http-equiv="x-ua-compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>login</title>
</head>
<body>
<h1>登录页面</h1>
<h1>This is login page!</h1>
<a href="https://blog.csdn.net/qq_41964425/article/category/8083068" target="_blank">CSDN</a>

<p>时间:@@xx@@</p>    <!--提前定义好特殊符号-->
</body>
</html>

Python代码:

from time import strftime
from socket import *

sk = socket(AF_INET, SOCK_STREAM)
sk.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
sk.bind(('127.0.0.1', 8080))
sk.listen()


# 将返回不同的内容部分封装成函数
def index(url):
    with open('index.html', 'rb') as f: return f.read()


def home(url):
    with open('home.html', 'rb') as f: return f.read()


# 实现动态网页
def login(url):
    now_time = str(strftime('%F %T'))
    with open('login.html', 'r', encoding='UTF-8') as f:
        s = f.read()
    # 在网页中定义好特殊符号,用动态的数据去替换定义好的特殊符号
    s = s.replace('@@xx@@', now_time)
    return bytes(s, encoding='UTF-8')


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

while True:
    # ------------ 建立连接 接收消息 ------------
    conn, addr = sk.accept()
    data = conn.recv(8096)

    # ------------ 对客服端发来的消息做处理 ------------
    # 把收到的字节类型的数据转换成字符串
    data_str = str(data, encoding='UTF-8')
    first_line = data_str.split('\r\n')[0]  # 按\r\n分隔
    url = first_line.split()[1]  # 在按空格切割

    # ------------ 业务逻辑处理部分 ------------
    func = None
    for i in url_list:
        if url == i[0]:
            func = i[1]
            break
    response = func(url) if func else b'404 not found!'

    # ----------- 回复响应消息 -----------
    conn.send(b'HTTP/1.1 200 OK\r\n\r\n')  # 响应状态行
    conn.send(response)
    conn.close()

服务器和应用程序

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

服务器程序负责对socket服务器进行封装,并在请求到来时,对请求的各种数据进行整理;应用程序则负责具体的逻辑处理.

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

如此,服务器程序就需要为不同的框架提供不同的支持。这样混乱的局面无论是对于服务器还是框架,都是不好的。

At this time, standardization becomes particularly important, we can set up a standard, as long as the server supports this standard, the framework also supports this standard, then they can be used together. Once the standard is determined, each of the parties to achieve.

WSGI (Web Server Gateway Interface) is a specification. It defines the interface between the format written in Python Web applications and Web server program, decoupling between Web applications and Web server program.

Commonly used WSGI server has uwsgi, Gunicorn. WSGI server independent Python standard library called wsgiref, == Django development environment is the use of this module to do the server. ==

wsgiref module

Use wsgiref module replaces write our own Web frameworks socket server part:

login function corresponds to the file:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta http-equiv="content-Type" charset="UTF-8">
    <meta http-equiv="x-ua-compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>login</title>
</head>
<body>
<h1>登录页面</h1>
<h1>This is login page!</h1>
<a href="https://blog.csdn.net/qq_41964425/article/category/8083068" target="_blank">CSDN</a>

<p>时间:@@xx@@</p>    <!--提前定义好特殊符号-->
</body>
</html>

Python code:

from time import strftime
from wsgiref.simple_server import make_server


# 将返回不同的内容部分封装成函数
def index(url):
    with open('index.html', 'rb') as f: return f.read()


def home(url):
    with open('home.html', 'rb') as f: return f.read()


def login(url):
    """实现动态网页"""
    now_time = str(strftime('%F %T'))  # 获取当前格式化时间
    with open('login.html', 'r', encoding='UTF-8') as f:
        s = f.read()
    # 在网页中定义好特殊符号,用动态的数据去替换定义好的特殊符号
    s = s.replace('@@xx@@', now_time)
    return bytes(s, encoding='UTF-8')


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


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

    func = None
    for i in url_list:
        if url == i[0]:
            func = i[1]
            break
    response = func(url) if func else b'404 not found!'

    return [response, ]


if __name__ == '__main__':
    httpd = make_server('127.0.0.1', 8080, run_server)
    print('Wsgiref has started...')
    httpd.serve_forever()

"

Original: http://blog.gqylpy.com/gqy/258

Guess you like

Origin www.cnblogs.com/bbb001/p/11367259.html