django-socket跟浏览器通信、wsgiref服务器、jinja2渲染库

socket跟浏览器通信

所有的Web应用本质上就是一个socket服务端,而用户的浏览器就是一个socket客户端。 这样我们就可以自己实现Web框架了。
每个HTTP请求和响应都遵循相同的格式,一个HTTP包含Header和Body两部分,其中Body是可选的。 HTTP响应的Header中有一个 Content-Type表明响应的内容格式。如 text/html表示HTML网页

HTTP GET请求的格式:
使用 \r\n分隔多个header

GET /path HTTP/1.1
header1:v1\r\n
header2:v2\r\n

HTTP POST请求格式:

POST /path HTTP/1.1
header1:v1\r\n
header2:v2\r\n
\r\n\r\n
请求体...

当遇到连续两个 \r\n\r\n时,表示Header部分结束了,后面的数据是Body。

HTTP响应的格式



200 OK
Header1:v1\r\n
Header2:v2\r\n
\r\n\r\n
响应体...

我们通过socket来实现一下交互功能:

import socket

sk = socket.socket()
sk.bind(("127.0.0.1", 8070))
sk.listen(5)

while True:
    conn, addr = sk.accept()
    data = conn.recv(8096)
    print("data-->",data)  # data是浏览器传过来的请求信息,bytes类型

    data_str = str(data, encoding="utf8")
    print("data_str",data_str)

    l1 = data_str.split("\r\n")
    print("l1",l1)

    l2 = l1[0].split()
    print("l2",l2)


    url = l2[1]
    print("url",url)
    # 根据url的不同,返回不同的内容
    if url == "/index/":
        body = "这是index页面"
    elif url == "/home/":
        body = "这是home页面"
    else:
        body = "404找不到"
    # 服务端回复消息
    conn.send(bytes("HTTP/1.1 200 OK\r\nContent-Type:text/html; charset=utf-8"
                    "\r\n\r\n<h1>{}</h1>".format(body), encoding="utf8"))
    conn.close()

以下是运行结果:
这里写图片描述

我们来看下pycharm里面的日志信息:

data--> b'GET /home/ HTTP/1.1\r\nHost: 127.0.0.1:8070\r\nUser-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:57.0) Gecko/20100101 Firefox/57.0\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\nAccept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2\r\nAccept-Encoding: gzip, deflate\r\nConnection: keep-alive\r\nUpgrade-Insecure-Requests: 1\r\n\r\n'
data_str GET /home/ HTTP/1.1
Host: 127.0.0.1:8070
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:57.0) Gecko/20100101 Firefox/57.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Connection: keep-alive
Upgrade-Insecure-Requests: 1


l1 ['GET /home/ HTTP/1.1', 'Host: 127.0.0.1:8070', 'User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:57.0) Gecko/20100101 Firefox/57.0', 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', 'Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2', 'Accept-Encoding: gzip, deflate', 'Connection: keep-alive', 'Upgrade-Insecure-Requests: 1', '', '']
l2 ['GET', '/home/', 'HTTP/1.1']
url /home/

wsgiref

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

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

from wsgiref.simple_server import make_server

def index():
    return "这是index页面"

def home():
    return "这是home页面"

def login():
    with open("login.html", encoding="utf8") as f:
        data = f.read()
    return data

URL_FUNC = [
    ("/index/", index),
    ("/home/", home),
    ("/login/", login),
]

def run_server(environ, start_response):
    start_response('200 OK', [('Content-Type', 'text/html;charset=utf8')])  # 设置HTTP响应的状态码和头信息
    url = environ['PATH_INFO']  # 取到用户输入的url
    print("--->url:", url)
    # 根据url的不同,返回不同的内容
    func_name = None
    for i in URL_FUNC:
        if url == i[0]:  # 如果能找到对应关系,就把函数名拿到
            func_name = i[1]
            break
    # 拿到可以执行的函数,执行函数拿到结果
    if func_name:
        body = func_name()
    else:
        body = "404找不到这个页面"

    return [bytes("<h1>{}</h1>".format(body), encoding="utf8"),]


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

这里写图片描述

控制台输出如下:

--->url: /login/
127.0.0.1 - - [11/Jan/2018 16:59:32] "GET /login/ HTTP/1.1" 200 281
--->url: /favicon.ico
127.0.0.1 - - [11/Jan/2018 16:59:32] "GET /favicon.ico HTTP/1.1" 200 33

jinja2

通过实现下载安装

pip install jinja2
from wsgiref.simple_server import make_server
import jinja2


def userlist():
    with open("login.html", encoding="utf8") as f:
        data = f.read()
    # 生成了一个jinja2的模板对象
    template = jinja2.Template(data)
    # 相当于字符串替换
    new_data = template.render({
        "user_list": [
            {"name": "wyf", "pwd": "1234"},
            {"name": "safly", "pwd": "5678"}
        ]
    })
    return new_data

URL_FUNC = [
    ("/login/", userlist),
]

def run_server(environ, start_response):
    start_response('200 OK', [('Content-Type', 'text/html;charset=utf8')])  # 设置HTTP响应的状态码和头信息
    url = environ['PATH_INFO']  # 取到用户输入的url
    print("--->url:", url)
    # 根据url的不同,返回不同的内容
    func_name = None
    for i in URL_FUNC:
        if url == i[0]:  # 如果能找到对应关系,就把函数名拿到
            func_name = i[1]
            break
    # 拿到可以执行的函数,执行函数拿到结果
    if func_name:
        body = func_name()
    else:
        body = "404找不到这个页面"

    return [bytes("<h1>{}</h1>".format(body), encoding="utf8"),]


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

login.html模板代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Title</title>
</head>
<body>
<ul>
    {% for user in user_list %}
    <li>{{user.name}}|{{user.pwd}}</li>
    {% endfor %}
</ul>
</body>
</html>

浏览器输出如下:
这里写图片描述

展开阅读全文

没有更多推荐了,返回首页