##web请求流程
#1、软件开发架构
c/s架构
客户端
服务端
b/s架构
浏览器
服务器
本质:b/s架构其实也是c/s架构
#2、问题:当我们在浏览器中输入一个url地址的时候, 按下回车的那一刹那, 比如ww.baidu.com 描述一下具体的过程. 首先我们通过DNS域名解析服务器对该域名进行解析,解析顺序先找本地dns服务器,比如window系统中host文件,找不到就找根域名解析服务器,全球总共十三台,然后依次找顶级域名服务器.com、权威域名服务器baidu.com、然后二级域名服务器www,当找到www.baidu.com对应的IP地址以后,便向该服务器发送请求,服务器反馈一个响应结果 #3、Http协议介绍
超文本传输协议:规定了客户端与服务端消息传输的格式
#3-1、四大特性:
1.基于TCP/IP协议作用于应用层的协议
2.基于请求响应
3.无状态
4.无连接
#3-2、数据格式之请求:
请求首行
请求头(一堆k,v键值对)
请求体(post请求携带的数据)
请求头: GET / HTTP/1.1 Host: 127.0.0.1:8080 (主机名) Connection: keep-alive (保持链接) Cache-Control: max-age=0 (缓存不失效) Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3 Accept-Encoding: gzip, deflate, br Accept-Language: zh-CN,zh;q=0.9 Token: bdsjalbdjsalbdjsa 请求体(两个换行符\r\n\r\n后面的内容): bdsabdjsabjddas
#3-3、数据格式之响应:
响应首行
响应头(一堆k,v键值对)
响应体(post请求携带的数据)
响应头: HTTP/1.1 200 OK 响应体: 自己看到的内容 ps: http: 默认端口是80 Https: 默认的端口是443 状态码:(*****************************)
1XX:服务器已经成功接受到你的数据正在处理,你可以继续提交其他数据 2XX: 200 (ok)请求成功 服务器已经将你请求的数据发送给你了 3XX: 302 304重定向 4XX: 404(not found) 403(forbidden 禁止访问)请求资源不存在 5XX: 500 (服务端代码错误) 502 (网关错误 bad gateway) #4、字符串和字节的转换: >>> s = "hello" >>> s 'hello' >>> bytes(s,encoding='utf-8') b'hello' >>> b = bytes(s,encoding='utf-8') >>> str(b, encoding='utf-8')
##自定义web框架
#1、需求:想要通过输入不同的 url, 获得不一样的相应内容 #解决思路: #step 1、创建sokect 服务端: 该socket服务器接收浏览器客户端发来的请求头中获取uri路径,运用了split方法取值 #step 2、路由系统: uri 和 函数的 对应关系 :(注意自定义的原因,这里读每一个html文件都需要自己打开进行读,然后函数return进行返回) routes = [ ('/xxx', f1), ('/ooo', f2), ('/hhh', f3) ] #step 3、模板引擎渲染,显示给用户 将html代码和mysql的数据进行手动融合,然后再替换html中自定义的内容,比如案例中自定义内容@@content@@
(自己定制规则需要自己拼接格式 , 或者使用第三方的工具,比如jinjia2模块)
后端生成的数据直接传递给前端页面使用(并且前端页面可以灵活的操作改数据) >>> 模板语法
模板渲染 模板语法需要依赖于第三方模块
pip install jinja2
templates:改文件夹存放就是所有的页面文件(.html)
模板语法 jinja2支持前端直接使用类似于python的语法操作数据
{{ user_dic }}
{{ user_dic.name }}
{{ user_dic['password'] }}
{{ user_dic.get('name') }}
{% for user in user_dict %}
{{ user.id }}
{{ user.name }}
{{ user.password }}
{% endfor %} #案例 *****自定制server.py***** import socket import time def f1(): fp = open('index.html','r',encoding='utf-8') data = fp.read() fp.close() return bytes(data,encoding='utf-8') def f2(): fp = open('article.html','r',encoding='utf-8') data = fp.read() ctime = time.time() data = data.replace('@@content@@',str(ctime)) return bytes(data, encoding='utf-8') def f3(): import pymysql conn = pymysql.connect(host='127.0.0.1',user='root',password='123',db='db1',charset='utf8') cursor = conn.cursor(cursor=pymysql.cursors.DictCursor) sql = 'select id,name,depart_id from userinfo' cursor.execute(sql) res = cursor.fetchall() print(res) res_list = [] for user in res: res_str = ""%(user["id"],user['name'],user["depart_id"]) res_list.append(res_str) s="".join(res_list) fp = open('content.html','r',encoding='utf-8') data = fp.read() fp.close() data = data.replace("@@content@@", s) return bytes(data,encoding='utf-8') def f4(): import pymysql conn = pymysql.connect(host='127.0.0.1',user='root',password='123',db='db1',charset='utf8') cursor = conn.cursor(cursor=pymysql.cursors.DictCursor) sql = 'select id,name,depart_id from userinfo' cursor.execute(sql) users = cursor.fetchall() # print(res) fp = open('content-jinjia2.html','r',encoding='utf-8') data = fp.read() fp.close() from jinja2 import Template template = Template(data) data = template.render(users = users) return bytes(data,encoding='utf-8') routers = ( ('/ooo',f1), ('/xxx',f2), ('/hhh',f3), ('/kkk',f4) ) def run(): server = socket.socket() server.bind(("127.0.0.1",1688)) server.listen(5) while True: client,addr = server.accept() buf = client.recv(1024) data = str(buf,encoding='utf-8') header_list = data.split('\r\n\r\n')[0].split('\r\n')[0] uri = header_list.split(' ')[1] #第一种方式:缺点:扩展性差 # res = None # if uri == '/xxx': # res = bytes("this is xxx",encoding='utf-8') # elif uri == '/ooo': # res = bytes("this is ooo", encoding='utf-8') # else: # res = bytes('404 not fund',encoding='utf-8') #第二种:路由方式 func_name = None for item in routers: if uri == item[0]: func_name = item[1] break if func_name: res = func_name() else: res = b'404 not fund' client.send(bytes('HTTP/1.1 200 OK\r\n\r\n',encoding='utf-8')) client.send(res) client.close() if __name__ == '__main__': run() *************index.html 静态显示********** "en"> "UTF-8"> %s %s %s Title this is index
***********article.html 可以替换自定义内容动态显示时间********** "en"> "UTF-8">Title @@content@@ *********content.html 可以替换自定义显示内容********* "en"> "UTF-8">Title
ID | Name | department_id |
---|
ID | Name | department_id |
---|---|---|
{{item.id}} | {{item.name}} | {{item.depart_id}} |
#2、web框架分类:
a. sokect 服务端 b、路由系统 c、模板引擎渲染
第一种维度分类:
- a,b,c ----> tornado
- a(用第三方), b, c ----> django wsgiref uwsgi
- a(第三方),b, c(第三方) -----》 flask
注:
web服务网关接口
WSGI协议
wsgiref(django自带的 可承受的并发量不是很高 通常指用于本地测试)
uwsgi (django项目上线之后会使用)
werkzeug (flask使用的)
实现WSGI协议的功能模块
ps:
请求来的时候处理http格式的数据
请求走的时候讲后端发送的数据打包成符合http格式的数据再发送
WSGI协议
wsgiref(django自带的 可承受的并发量不是很高 通常指用于本地测试)
uwsgi (django项目上线之后会使用)
werkzeug (flask使用的)
实现WSGI协议的功能模块
ps:
请求来的时候处理http格式的数据
请求走的时候讲后端发送的数据打包成符合http格式的数据再发送
python三大主流web框架
Django:大而全,自带了很多功能模块,类似于航空母舰 (缺点:有点笨重)
Flask:短小精悍,自带的功能模块特别少,大部分都是依赖于第三方模块(小而轻)
Tornado:异步非阻塞 主要用在处理高io 多路复用的情况 可以写游戏后端
第二种维度:
- django
- 其他
##Django基础
#1、安装: pip3 install django==1.11.10 -i https://pypi.tuna.tsinghua.edu.cn/simple #2、创建: 创建django项目的方式
方式1(命令行创建):
创建django项目
django-admin startproject 项目名
创建app应用
python3 manage.py startapp app01
启动django项目
python3 manage.py runserver
ps:用命令行创建django默认不会自动创建templates文件夹
需要你手动自己创建(注意改文件夹路径是否被添加配置文件中)
方式2(pycharm创建)
FILE >>> new project 选择第二个django 需要注意名字不能有中文,选择本地的解释器,勾选后台管理
创建app
pycharm命令行创建
python3 manage.py startapp app01
Tools下面run manage task功能栏
启动点小绿色箭头
强调:
1.用django一定要保证只有一个在运行状态 切记切记!!!!!!!
2.一定记得清浏览器的缓存
app(应用)的概念
一个django项目就是一所大学
app就是大学里面的学院
注意新创建的app需要在配置文件中注册才能生效(*******************)
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'app01.apps.App01Config' # 可以用全称
'app01' # 也可以简写
] #3、目录介绍: 应用名
migrations 数据库迁移记录相关数据
admin.py django后台管理相关
models.py 模型表相关
views.py 视图函数相关 mysite: mysite项目名: settings.py : 用户自定义的各种配置 urls.py : 路由与视图含书映射关系 wsgi.py : 启动socket服务端的 文件 mange.py: django入口文件、 管理文件、 python mange.py 各种命令
templates:项目用到的所有的html文件 js, css, img : 静态 文件 #4、以后创建django完成之后: a. 配置末班文件路径: 'DIRS': [os.path.join(BASE_DIR, 'templates')] b. 配置静态资源的文件路径: STATIC_URL = '/static/' STATICFILES_DIRS = ( os.path.join(BASE_DIR, 'static'), (逗号不能少) ) c. 注释中间件 MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', #'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', ]
#5、写业务逻辑的话:
uri和函数的对应关系:
urlpatterns = [
# url(r'^admin/', admin.site.urls),
url(r'^index/', index),
]
业务逻辑函数:
def index(request):
return render(request, "index.html")
##Django + 前端表单提交数据到后台
#django小白必会三板斧
# HttpResponse:它是作用是内部传入一个字符串参数,然后发给浏览器。 # render:render方法可接收三个参数,一是request参数,二是待渲染的html模板文件,三是保存具体数据的字典参数。 它的作用就是将数据填充进模板文件,最后把结果返回给浏览器。与jinja2类似。 #redirect 重定向 又走了一次网络请求 注意:django必会三板斧返回的都是HttpReponse对象
#1、创建一个Django项目(功能:数据库验证登录、登陆失败标红从新渲染、登陆成功跳转) #1-1、完成三件事(上述有讲解 ,此处省略) #1-2、路由文件urls.py中 添加路由 urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^index/',index), url(r'^login/',login), ] 创建相对应函数 def index(request): return render( request, 'index.html', { "username":"icon", "mylist":["icon",'is','18'], "mydict":{"name":"icon","age":"18"}, "userinfo":[ {"name":"icon1","age":"18","sex":"male"}, {"name":"icon2","age":"19","sex":"male"}, {"name":"icon3","age":"20","sex":"male"}, {"name":"icon4","age":"21","sex":"male"}, ] }, ) def login(request): if request.method == 'GET': return render(request,'login.html') else: import pymysql conn = pymysql.connect(host='127.0.0.1', user='root', password='123', db='db1', charset='utf8') cursor = conn.cursor(cursor=pymysql.cursors.DictCursor) sql = 'select * from user' cursor.execute(sql) # 数据库数据列表套字典 users = cursor.fetchall() #前端传过来的用户信息和密码 username = request.POST.get('username') password = request.POST.get('password') for user in users: if username == user.get('username') and password == user.get('password'): return HttpResponseRedirect("/index/") return render(request,'login.html',{'error_msg':'用户名或密码错误'}) #1-3、在templates目录创建index.html文件 "en"> "UTF-8">Title {#1、渲染:变量替换,替换的key必须和urls.py文件中一一对应#} {{ username }}
{#2、渲染:列表替换#} {#{{ mylist.0 }}#} {#{{ mylist.1 }}#} {#{{ mylist.2 }}#}
- {{ mylist.0 }}
- {{ mylist.1 }}
- {{ mylist.2 }}
{#3、渲染:列表循环替换#}
-
{% for item in mylist %}
- {{ item }} {% endfor %}
{#4、渲染:字典循环替换显示给用户#} {% for key,val in mydict.items %}
{% for key in mydict.keys %}
{#5、渲染:表格#}
name | age | sex |
---|---|---|
{{ user.name }} | {{ user.age }} | {{ user.sex }} |