web介绍以及自定义框架

本文介绍了web的基本概念,包括web前端与后端开发。接着讲解了软件开发的C/S和B/S架构,重点阐述了web框架的本质——socket服务端与浏览器的通讯。文章还展示了如何自定义一个简单的web框架,并探讨了动态网页的实现方法。最后提到了Python中的WSGI协议及其重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1 什么是web?

web指的是网络,web应用开发指的是基于网络的应用程序开发。
Web应用开发分为web前端开发和web后端开发。
Web前端开发:我们可以简单的理解为开发一些网页。
Web后端开发:写一些逻辑判断程序。
当用户发出请求给我们写的程序,程序根据用户的请求做出相应的判断,然后返回给客户相应的内容。

2 软件开发架构

两个程序之间通讯的应用大致可以分为两种:
第一种是应用类程序:qq、微信、网盘、优酷这一类是属于需要安装的桌面应用
第二种是web类程序:用户只需要浏览器即可访问程序。常见的web类应用程序
比如百度、知乎、优快云等使用浏览器访问就可以直接使用。
不管是应用类程序还是web类程序,这些应用的本质其实都是两个程序之间的通讯。
而这两个分类又对应了两个软件开发的架构~

1、客户端服务器概念

客户端:就是我们常用的程序例如qq、微信,浏览器等等。
服务器:要一直运行着给别人提供服务的机器。
例如现在我使用的CTS软件给同学们提供服务,我的电脑就是服务端(服务器)

2、C/S架构

C/S即:Client与Server ,中文意思:客户端与服务器端架构。
这里的客户端一般泛指客户端应用程序exe,程序需要先安装后,才能运行在用户的电脑上,对用户的电脑操作系统环境依赖较大。
在这里插入图片描述
3、B/S架构

B/S即:Browser与Server,中文意思:浏览器端与服务器端架构。只需在浏览器上通过HTTP去请求服务器端相关的资源(网页资源)。
在这里插入图片描述
执行流程:
浏览器发出一次请求给服务端,服务端通过逻辑判断把相应的数据发送给客户端。
依次执行上面的流程。

3 web框架

1、什么是框架
在生活中就像我们想到的一样,框架指的我们在做一件事情的时候搭的骨架来完成基础的功能。
程序中的框架和生活中搭建的框架的功能是相同的,框架来完成一些基础的工作,
程序员在此基础上开发实现自己业务功能的代码;
把程序员从繁琐的重复性的代码中解脱出来,提交开发效率;

2 web框架的本质

我们可以这样理解:所有的Web应用框架本质上就是一个socket服务端,而用户的浏览器就是一个socket客户端。 一些常用框架(Django、Tornado、Flash)是对socket服务端进行的封装,使得基础功能更加完善。

这样我们就可以自己实现Web框架了。
(1).自定义web框架(不完整版)

import socket

server_sk = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

server_sk.bind(('127.0.0.1', 9999))
server_sk.listen(128)
while True:
    new_sk, addr = server_sk.accept()
    content = new_sk.recv(1024)
    print('接受到了数据...')
    print(content)
    # 给浏览器发生内容
    new_sk.send(b'HTTP/1.1 200 ok\r\n\r\n')  # 设置协议格式
    new_sk.send(b'ok')
    new_sk.close()

我们通过十几行代码简单地演示了web 框架的本质。
在这里插入图片描述
扩展:
1.解决返回给浏览器中文乱码问题:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
(2).根据不同的路径返回不同的内容
如何让我们的Web服务根据用户请求的URL不同而返回不同的内容呢?
小事一桩,我们可以从请求相关数据里面拿到请求URL的路径,然后拿路径做一个判断…

import socket

server_sk = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_sk.bind(('127.0.0.1', 9999))
server_sk.listen(128)
while True:
    new_sk, addr = server_sk.accept()
    content = new_sk.recv(1024)
    content = content.decode(encoding='UTF-8')
    # print(content)
    # 1.根据\r\n 进行切割 获取 请求首行
    data = content.split('\r\n')[0]  # GET /index HTTP/1.1
    # print(data)
    # 2.根据空格进行切割,获取路径 /index
    data = data.split()[1]
    print(data)
    new_sk.send(b'HTTP/1.1 200 ok\r\n\r\n')
    if data == '/index':
        response = b'index'
    elif data == '/home':
        response = b'home'
    else:
        response = b'404 not found...'
    new_sk.send(response)

    new_sk.close()

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
(3).根据不同的路径返回不同的内容–函数版
上面的代码解决了不同URL路径返回不同内容的需求。
但是问题又来了,如果有很多很多路径要判断怎么办?难道要挨个写if判断? 当然不用,我们有更聪明的办法。

import socket

sever_sk = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sever_sk.bind(('127.0.0.1', 9999))
sever_sk.listen(128)


# 使用函数
def index(url):
    s = '这是{}页面'.format(url)
    return s.encode('utf-8')


# 使用函数
def home(url):
    s = '这是{}页面'.format(url)
    return s.encode('utf-8')


while True:
    new_sk, addr = sever_sk.accept()
    content = new_sk.recv(1024)
    content = content.decode(encoding='utf-8')
    data = content.split('\r\n')[0]
    data = data.split()[1]
    # print(data)
     if data == '/index':
        response = index(data
    elif data == '/home':
        response = home(data)
    else:
        response = b'404 not found...'

    new_sk.send(b'HTTP/1.1 200 OK\r\n')
    # 如果浏览器乱码则添加相应头信息。
    new_sk.send(b'Content-Type: text/html;charset=utf-8\r\n')
    new_sk.send(b'\r\n')
    new_sk.send(response)
    new_sk.close()

(4).根据不同的路径返回不同的内容–函数进阶版
看起来上面的代码还是要挨个写if判断,怎么办?我们还是有办法!

import socket

sever_sk = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sever_sk.bind(('127.0.0.1', 9999))
sever_sk.listen(128)


def index(url):
    s = '这是{}页面'.format(url)
    return s.encode('utf-8')


def home(url):
    s = '这是{}页面'.format(url)
    return s.encode('utf-8')


# 1.定义一个url和执行函数对应关系的列表
url_func_lst = [
    ('/index', index),
    ('/home', home)
]
while True:
    new_sk, addr = sever_sk.accept()
    content = new_sk.recv(1024)
    content = content.decode(encoding='utf-8')
    data = content.split('\r\n')[0]
    url = data.split()[1]
    # 2.定义一个变量来接受对应的函数名称
    func = None
    # 3.变量列表,查收是否有对应的url
    for url_func in url_func_lst:
        if url_func[0] == url:
            func = url_func[1]
    if func:
        response = func(url)
    else:
        response = b'404 not found...'

    new_sk.send(b'HTTP/1.1 200 OK\r\n')
    new_sk.send(b'Content-Type: text/html;charset=utf-8\r\n')
    new_sk.send(b'\r\n')
    new_sk.send(response)
    new_sk.close()

(5).返回具体的HTML文件
完美解决了不同URL返回不同内容的问题。 但是我不想仅仅返回几个字符串,我想给浏览器返回完整的HTML内容,这又该怎么办呢?
没问题,不管是什么内容,最后都是转换成字节数据发送出去的。 我们可以打开HTML文件,读取出它内部的二进制数据,然后再发送给浏览器。

import socket

sever_sk = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sever_sk.bind(('127.0.0.1', 9999))
sever_sk.listen(128)


# 1.读取 index.html中的内容
def index(url):
    with open('index.html', mode='rb') as  f:
        data = f.read()
    return data
    rl_func_lst = [
    ('/index', index),
    ('/home', home)
]

while True:
    new_sk, addr = sever_sk.accept()
    content = new_sk.recv(1024)
    content = content.decode(encoding='utf-8')
    data = content.split('\r\n')[0]
    url = data.split()[1]
    func = None
    for url_func in url_func_lst:
        if url_func[0] == url:
            func = url_func[1]
    if func:
        response = func(url)
    else:
        response = b'404 not found...'

    new_sk.send(b'HTTP/1.1 200 OK\r\n')
    new_sk.send(b'Content-Type: text/html;charset=utf-8\r\n')
    new_sk.send(b'\r\n')
    new_sk.send(response)
    new_sk.close()

(6).让网页动态起来

这网页能够显示出来了,但是都是静态的啊。页面的内容都不会变化的,我想要的是动态网站。
没问题,我也有办法解决。我选择使用字符串替换来实现这个需求。(这里使用时间戳来模拟动态的数据)


# 1.导入time模块
import socket, time

sever_sk = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sever_sk.bind(('127.0.0.1', 9999))
sever_sk.listen(128)


# 2.替换页面中的内容
def index2(url):
    with open('index2.html', mode='r', encoding='UTF-8') as f:
        data = f.read()
        data = data.replace('xxooxx', str(time.time()))
        data = bytes(data, encoding='utf-8')
    return data


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


url_func_lst = [
    ('/index2', index2),
    ('/home', home)
]

while True:
    new_sk, addr = sever_sk.accept()
    content = new_sk.recv(1024)
    content = content.decode(encoding='utf-8')
    data = content.split('\r\n')[0]
    url = data.split()[1]
    func = None
    for url_func in url_func_lst:
        if url_func[0] == url:
            func = url_func[1]
    if func:
        response = func(url)
    else:
        response = b'404 not found...'
    new_sk.send(b'HTTP/1.1 200 OK\r\n')
    new_sk.send(b'Content-Type: text/html;charset=utf-8\r\n')
    new_sk.send(b'\r\n')
    new_sk.send(response)
    new_sk.close()

(7).总结
总结
1.web框架的本质:socket 服务端 与浏览器的通讯。
2.socket 服务端功能可以划分为3部分:

  • a.负责与浏览器收发消息(socket)在python中有专门的框架
    wsgiref/uWsgi/gunicorn…
  • b.根据用户访问不同的路径执行不同的函数
  • c.从HTML中读取出内容,并且完成字符串的替换
    3.Python中 web 框架的分类:
  • 按照2上面的功能分类
    (1).框架自带a,b,c 功能 ----> Tornado
    (2).框架自带b,c,使用第三方的a ---->Django
    (3).框架自带b,使用第三方的a,c ---->Flask
    -按照另一个维度划分
    (1).Diango ,Tornado–>大而全(做一个网站用到的技术都有)
    (2).其他 例如 Flask 轻量级只封装了核心功能。
    a部分和b、c 部分通讯需要遵守WSGI 协议。

四、WSGI
总体可以分为两部分功能,一部分是负责接受客户端信息的server socket代码,我们叫他服务器程序 ,一部分是进行逻辑判断代码我们叫做应用程序。

在这里插入图片描述
刚才我们已经分析了Django框架,Django框架是应用程序,负责业务逻辑,本身没有服务器程序功能。现有有很多优秀的服务器程序 例如 uwsgi、Gunicorn。而Web应用框架和服务器程序进行配合使用就需要遵循一定的规范(就比如图中的桥梁部分)。而这个规范就是WSGI
WSGI(Web Server Gateway Interface, Web服务器网关接口) 就是一种规范,
它定义了使用Python编写的web应用程序与web服务器程序之间的接口格式,实现web应用程序与web服务器程序间的配合。
在这里插入图片描述
服务器和应用框架都遵循了WSGI协议后,就可以任意组合了更加灵活。
而Python标准库提供的独立WSGI服务器叫wsgiref,Django开发环境用的就是这个模块来做服务器。

1.简单使用wsgiref模块

import socket, time
# 1.导入模块
from wsgiref.simple_server import make_server


def index2(url):
    with open('index2.html', mode='r', encoding='UTF-8') as f:
        data = f.read()
        data = data.replace('xxooxx', str(time.time()))
        data = bytes(data, encoding='utf-8')
    return data


url_func_lst = [
    ('/index2', index2),
]


def server(environ, start_response):
    """
    :param environ:字典类型,封装了一些内容,其中包括URL请求路径。参数名称任意
    :param start_response: 是一个函数地址,返回响应头。名称任意
    :return:列表类型, 返回响应体内容。
    """
    print('-->>>', environ)
    # 封装响应头信息,服务器程序自动调用
    start_response('200 OK', [('Content-Type', 'text/html;charset=utf-8')])
    # 取到用户输入的url
    url = environ['PATH_INFO']
    func = None
    for url_func in url_func_lst:
        if url_func[0] == url:
            func = url_func[1]
    if func:
        response = func(url)
    else:
        response = b'404 not found...'

    return [response, ]


# 2.使用
if __name__ == '__main__':
    # 设置ip和端口号,以及要调用的函数名称,名称任意。
    httpd = make_server('127.0.0.1', 9999, server)
    print('1111')
    # 永远开启,代替了while 死循环
    httpd.serve_forever()
    print('222')
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值