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

最简单的web框架

import socketsk = socket.socket()
sk.bind(("127.0.0.1", 80))
sk.listen()while True:conn, addr = sk.accept()data = conn.recv(8096)conn.send(b"OK")conn.close()

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

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

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

import socketsk = 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
Host: 127.0.0.1:8080
Connection: keep-alive
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
DNT: 1
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
Cookie: csrftoken=RKBXh1d3M97iz03Rpbojx1bR6mhHudhyX5PszUxxG3bOEwh1lxFpGOgWN93Z

响应相关信息可以在浏览器调试窗口的network标签页中看到。

点击view source之后显示如下图:

我们发现收发的消息需要按照一定的格式来,这里就需要了解一下HTTP协议了。

HTTP协议介绍

HTTP协议对收发消息的格式要求

每个HTTP请求和响应都遵循相同的格式,一个HTTP包含Header和Body两部分,其中Body是可选的。 HTTP响应的Header中有一个 Content-Type表明响应的内容格式。如 text/html表示HTML网页。

HTTP GET请求的格式:

HTTP响应的格式:

第一版自定义web框架

import socketsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind(('127.0.0.1', 8000))
sock.listen()while True:conn, addr = sock.accept()data = conn.recv(8096)# 给回复的消息加上响应状态行conn.send(b"HTTP/1.1 200 OK\r\n\r\n")conn.send(b"OK")conn.close()

根据不同的路径返回不同的内容

"""
根据URL中不同的路径返回不同的内容
"""import socket
sk = socket.socket()
sk.bind(("127.0.0.1", 8080))  # 绑定IP和端口
sk.listen()  # 监听while 1:# 等待连接conn, add = sk.accept()data = conn.recv(8096)  # 接收客户端发来的消息# 从data中取到路径data = str(data, encoding="utf8")  # 把收到的字节类型的数据转换成字符串# 按\r\n分割data1 = data.split("\r\n")[0]url = data1.split()[1]  # url是我们从浏览器发过来的消息中分离出的访问路径conn.send(b'HTTP/1.1 200 OK\r\n\r\n')  # 因为要遵循HTTP协议,所以回复的消息也要加状态行# 根据不同的路径返回不同内容if url == "/index/":response = b"index"elif url == "/home/":response = b"home"else:response = b"404 not found!"conn.send(response)conn.close()

根据不同的路径返回不同的内容--函数进阶版

"""
根据URL中不同的路径返回不同的内容--函数进阶版
"""import socket
sk = socket.socket()
sk.bind(("127.0.0.1", 8080))  # 绑定IP和端口
sk.listen()  # 监听# 将返回不同的内容部分封装成函数
def index(url):s = "这是{}页面!".format(url)return bytes(s, encoding="utf8")def home(url):s = "这是{}页面!".format(url)return bytes(s, encoding="utf8")# 定义一个url和实际要执行的函数的对应关系
list1 = [("/index/", index),("/home/", home),
]while 1:# 等待连接conn, add = sk.accept()data = conn.recv(8096)  # 接收客户端发来的消息# 从data中取到路径data = str(data, encoding="utf8")  # 把收到的字节类型的数据转换成字符串# 按\r\n分割data1 = data.split("\r\n")[0]url = data1.split()[1]  # url是我们从浏览器发过来的消息中分离出的访问路径conn.send(b'HTTP/1.1 200 OK\r\n\r\n')  # 因为要遵循HTTP协议,所以回复的消息也要加状态行# 根据不同的路径返回不同内容func = None  # 定义一个保存将要执行的函数名的变量for i in list1:if i[0] == url:func = i[1]breakif func:response = func(url)else:response = b"404 not found!"# 返回具体的响应消息
    conn.send(response)conn.close()

返回具体的HTML文件

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

没问题,不管是什么内容,最后都是转换成字节数据发送出去的。 我们可以打开HTML文件,读取出它内部的二进制数据,然后再发送给浏览器。

"""
根据URL中不同的路径返回不同的内容--函数进阶版
返回独立的HTML页面
"""import socket
sk = socket.socket()
sk.bind(("127.0.0.1", 8080))  # 绑定IP和端口
sk.listen()  # 监听# 将返回不同的内容部分封装成函数
def index(url):# 读取index.html页面的内容with open("index.html", "r", encoding="utf8") as f:s = f.read()# 返回字节数据return bytes(s, encoding="utf8")def home(url):with open("home.html", "r", encoding="utf8") as f:s = f.read()return bytes(s, encoding="utf8")# 定义一个url和实际要执行的函数的对应关系
list1 = [("/index/", index),("/home/", home),
]while 1:# 等待连接conn, add = sk.accept()data = conn.recv(8096)  # 接收客户端发来的消息# 从data中取到路径data = str(data, encoding="utf8")  # 把收到的字节类型的数据转换成字符串# 按\r\n分割data1 = data.split("\r\n")[0]url = data1.split()[1]  # url是我们从浏览器发过来的消息中分离出的访问路径conn.send(b'HTTP/1.1 200 OK\r\n\r\n')  # 因为要遵循HTTP协议,所以回复的消息也要加状态行# 根据不同的路径返回不同内容func = None  # 定义一个保存将要执行的函数名的变量for i in list1:if i[0] == url:func = i[1]breakif func:response = func(url)else:response = b"404 not found!"# 返回具体的响应消息
    conn.send(response)conn.close()

让网页动态起来

这网页能够显示出来了,但是都是静态的啊。页面的内容都不会变化的,我想要的是动态网站。

没问题,我也有办法解决。我选择使用字符串替换来实现这个需求。(这里使用时间戳来模拟动态的数据)

"""
根据URL中不同的路径返回不同的内容--函数进阶版
返回HTML页面
让网页动态起来
"""import socket
import timesk = socket.socket()
sk.bind(("127.0.0.1", 8080))  # 绑定IP和端口
sk.listen()  # 监听# 将返回不同的内容部分封装成函数
def index(url):with open("index.html", "r", encoding="utf8") as f:s = f.read()now = str(time.time())s = s.replace("@@oo@@", now)  # 在网页中定义好特殊符号,用动态的数据去替换提前定义好的特殊符号return bytes(s, encoding="utf8")def home(url):with open("home.html", "r", encoding="utf8") as f:s = f.read()return bytes(s, encoding="utf8")# 定义一个url和实际要执行的函数的对应关系
list1 = [("/index/", index),("/home/", home),
]while 1:# 等待连接conn, add = sk.accept()data = conn.recv(8096)  # 接收客户端发来的消息# 从data中取到路径data = str(data, encoding="utf8")  # 把收到的字节类型的数据转换成字符串# 按\r\n分割data1 = data.split("\r\n")[0]url = data1.split()[1]  # url是我们从浏览器发过来的消息中分离出的访问路径conn.send(b'HTTP/1.1 200 OK\r\n\r\n')  # 因为要遵循HTTP协议,所以回复的消息也要加状态行# 根据不同的路径返回不同内容func = None  # 定义一个保存将要执行的函数名的变量for i in list1:if i[0] == url:func = i[1]breakif func:response = func(url)else:response = b"404 not found!"# 返回具体的响应消息
    conn.send(response)conn.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部分:

"""
根据URL中不同的路径返回不同的内容--函数进阶版
返回HTML页面
让网页动态起来
wsgiref模块版
"""import time
from wsgiref.simple_server import make_server# 将返回不同的内容部分封装成函数
def index(url):with open("index.html", "r", encoding="utf8") as f:s = f.read()now = str(time.time())s = s.replace("@@oo@@", now)return bytes(s, encoding="utf8")def home(url):with open("home.html", "r", encoding="utf8") as f:s = f.read()return bytes(s, encoding="utf8")# 定义一个url和实际要执行的函数的对应关系
list1 = [("/index/", index),("/home/", home),
]def run_server(environ, start_response):start_response('200 OK', [('Content-Type', 'text/html;charset=utf8'), ])  # 设置HTTP响应的状态码和头信息url = environ['PATH_INFO']  # 取到用户输入的urlfunc = Nonefor i in list1:if i[0] == url:func = i[1]breakif func:response = func(url)else:response = b"404 not found!"return [response, ]if __name__ == '__main__':httpd = make_server('127.0.0.1', 8090, run_server)print("我在8090等你哦...")httpd.serve_forever()

三、Django

Django官网下载页面

3.1安装(安装最新LTS版):

pip3 install django==1.11.9

3.2创建一个django项目:

下面的命令创建了一个名为"mysite"的Django 项目:

在pycharm创建Django项目

3.2  目录介绍:

mysite/
├── manage.py  # 管理文件
└── mysite  # 项目目录├── __init__.py├── settings.py  # 配置├── urls.py  # 路由 --> URL和函数的对应关系└── wsgi.py  # runserver命令就使用wsgiref模块做简单的web server

3.4运行Django项目:

1)命令行运行Django项目

python manage.py runserver 127.0.0.1:8000

2)模板文件配置:

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',],},},
]

3.4静态文件配置:

STATIC_URL = '/static/'  # HTML中使用的静态文件夹前缀
STATICFILES_DIRS = [os.path.join(BASE_DIR, "static"),  # 静态文件存放位置
]

MIDDLEWARE = ['django.middleware.security.SecurityMiddleware','django.contrib.sessions.middleware.SessionMiddleware','django.middleware.common.CommonMiddleware',# 'django.middleware.csrf.CsrfViewMiddleware', #配置文件中暂时禁用csrf中间件,方便表单提交测试'django.contrib.auth.middleware.AuthenticationMiddleware','django.contrib.messages.middleware.MessageMiddleware','django.middleware.clickjacking.XFrameOptionsMiddleware',
]

3.5Django基础必备三件套:

from django.shortcuts import HttpResponse, render
  1. HttpResponse('字符串')
  2. render(request, 'xx.html') #打开一个文件,并响应给服务器
  3. redirect #从页面跳转另一个页面

3.5.1HttpResponse

内部传入一个字符串参数,返回给浏览器。

def index(request):# 业务逻辑代码return HttpResponse("OK")

3.5.2 render

除request参数外还接受一个待渲染的模板文件和一个保存具体数据的字典参数。

将数据填充进模板文件,最后把结果返回给浏览器。(类似于我们上面用到的jinja2)

例如:

def index(request):# 业务逻辑代码return render(request, "index.html", {"name": "alex", "hobby": ["烫头", "泡吧"]})

3.5.3 redirect

接受一个URL参数,表示跳转到指定的URL。

def index(request):# 业务逻辑代码return redirect("/home/")

转载于:https://www.cnblogs.com/Robi-9662/p/9448823.html

django框架基础相关推荐

  1. Django框架基础知识汇总(有项目版)

    Web框架本质## web系统概念 1. Http,无状态,短连接 2. 浏览器(socket客户端).网站(socket服务端) web框架本质 import socket def handle_r ...

  2. Django框架基础知识点

    Django框架 1.Django创建项目的命令 django-admin startproject 项目名称 python manage.py startapp 应用app名 2.Django创建项 ...

  3. Django框架基础学习

    Django安装 python下载地址 http://www.python.org/download/releases/3.3.4/ Django的下载地址:https://www.djangopro ...

  4. Django框架基础知识05-自定义模板标签与过滤器

    根据一定规则,自己定义出符合需求功能的.用在任何你有需求的地方,因为内置的满足不了我们的需求,不同的东西有不同的定义规则 目前最最重要的就是HOW 一 文件路径配置: templates 存放自定义 ...

  5. Django框架深入了解_01(Django请求生命周期、开发模式、cbv源码分析、restful规范、跨域、drf的安装及源码初识)

    阅读目录 一.Django请求生命周期: 二.WEB开发模式: 三.cbv源码分析: 四.认识RESTful 补充知识:跨域 五.基于原生django开发restful的接口 六.drf安装.使用.A ...

  6. python的django介绍_【Python基础知识】Django框架简介

    很多初学Python的小伙伴不知道该从何开始学起,其实零基础学习的话可以先学习一些Python基础知识,等基础打牢之后再去接触更加深入的技术,接下来小编就为大家简单介绍一下有关于 Django框架内容 ...

  7. Django框架学习--4--分布式路由ORM基础

    本篇文章要点: 1.如何通过分布式路由方法避免主路由文件的urlpatterns过于臃肿? 2.使用ORM框架代替数据库的操作? 1. Django的分布式路由实现 创建应用 应用在django项目中 ...

  8. python setting.py_python基础教程:Django框架的中的setting.py文件说明详解

    这篇文章主要介绍了Django框架的中的setting.py文件说明详解,这个文件包含了所有有关这个Django项目的配置信息,具有一定的参考价值,感兴趣的小伙伴们可以参考一下 1.加载数据库,数据库 ...

  9. python框架django文档_Django基础——Django框架介绍及模板语言

    Django框架,我们只需要关心二点: 1.根据用户访问不同的路径执行不同的函数 2.从HTML读取出内容,并且完成字符串的替换 而socket通信不需要我们自己写: 新建Django项目 命令行创建 ...

最新文章

  1. DataGrid连接Access的快速分页法(1)——需求与现状
  2. SKU表管理之删除SKU表数据
  3. 目标检测评价标准 精准度(precision)、召回率(recall)、准确率(accuracy)、交除并(IoU)【全】
  4. php7连接mongodb,批量添加数据
  5. 一句话讲清楚IOC容器以及什么时候使用@Autowired
  6. JSP中一个页面怎么分清是链接过来还是提交过来的?
  7. 计组学习笔记(一):浮点数的表示和运算
  8. put url带参数_一道腾讯面试题:如何快速判断某 URL 是否在 20 亿的网址 URL 集合中?...
  9. 数组----数组的拷贝、排序、遍历、引用,console交互
  10. 机器学习(6): 层次聚类 hierarchical clustering
  11. 不写一行代码,搭建Jenkins+Jmeter+Ant接口自动化框架
  12. 网站点赞 评论 回复 数据库设计
  13. 学点 C 语言(32): 函数 - 返回值
  14. 关于电子计算机的热点,电脑如何变热点?8款电脑wifi热点软件推荐
  15. steam服务器102修复,steam平台102代码错误怎么办 解决steam错误代码102图文教程
  16. 21届秋招美团一面面经[业务运营管理]
  17. 经济学计算机会成本和贸易区直的题,管理经济学2017年4月真题(02628)
  18. 手机中的RAM和ROM分别对应电脑的内存和硬盘
  19. 【浙大版《Python 程序设计》题目集(解)】第3章-14 字符串字母大小写转换(15分)
  20. 关于小程序网易云音乐接口用户登录,繁忙问题

热门文章

  1. Golang教程:(十五)指针
  2. 【十三】Jmeter:“CSV 数据文件设置”参数化请求中出现带有逗号的参数值
  3. win7美化_Windows桌面管理美化,让桌面更加方便、高效
  4. c语言程序设计教程第三版答案9.5,C语言程序设计-第5-9章习题解答.ppt
  5. 正则表达式匹配指定的tr标签
  6. 工作——常用语法记录
  7. Spring Boot RestTemplate 忽略证书访问https
  8. fiddler证书 iphone_【详细】Mac使用Fiddler实现IPhone抓包(支持https)
  9. java下载好怎么验证_Java JDK下载、安装和验证
  10. mysql java事物回滚吗_为什么 MySQL 回滚事务也会导致 ibd 文件增大?