Web框架本质

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

socket服务端

  1. import socket
  2. sk = socket.socket()
  3. sk.bind(("127.0.0.1", 80))
  4. sk.listen()
  5. while True:
  6. conn, addr = sk.accept()
  7. data = conn.recv(8096)
  8. conn.send(b"OK")
  9. conn.close()

可以说Web服务本质上都是在这十几行代码基础上扩展出来的。这段代码就是它们的祖宗。

用户在浏览器中输入网址,浏览器会向服务端发送数据,那浏览器会发送什么数据?怎么发?这个谁来定? 你这个网站是这个规定,他那个网站按照他那个规定,那互联网还能玩么?

所以,必须有一个统一的规则,让大家发送消息、接收消息的时候都有个格式依据,不能随便写。

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

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

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

  1. import socket
  2. sk = socket.socket()
  3. sk.bind(("127.0.0.1", 80))
  4. sk.listen()
  5. while True:
  6. conn, addr = sk.accept()
  7. data = conn.recv(8096)
  8. print(data)  # 将浏览器发来的消息打印出来
  9. conn.send(b"OK")
  10. conn.close()

输出:

b'GET / HTTP/1.1\r\nHost: 127.0.0.1:8080\r\nConnection: keep-alive\r\nCache-Control: max-age=0\r\nUpgrade-Insecure-Requests: 1\r\nUser-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3355.4 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\r\nCookie: csrftoken=CtHePYARJOKNx5oNVwxIteOJXpNyJ29L4bW4506YoVqFaIFFaHm0EWDZqKmw6Jm8\r\n\r\n'

我们将\r\n替换成换行看得更清晰点:

  1. GET / HTTP/1.1
  2. Host: 127.0.0.1:8080
  3. Connection: keep-alive
  4. Cache-Control: max-age=0
  5. Upgrade-Insecure-Requests: 1
  6. User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3355.4 Safari/537.36
  7. Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
  8. Accept-Encoding: gzip, deflate, br
  9. Accept-Language: zh-CN,zh;q=0.9
  10. Cookie: csrftoken=CtHePYARJOKNx5oNVwxIteOJXpNyJ29L4bW4506YoVqFaIFFaHm0EWDZqKmw6Jm8

然后我们再看一下我们访问博客园官网时浏览器收到的响应信息是什么。

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

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

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

HTTP协议介绍

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

每个HTTP请求和响应都遵循相同的格式,一个HTTP包含Header和Body两部分,其中Body是可选的。

HTTP响应的Header中有一个 Content-Type表明响应的内容格式。它的值如text/html; charset=utf-8。

text/html则表示是网页,charset=utf-8则表示编码为utf-8。

HTTP GET请求的格式:

HTTP响应的格式:

自定义web框架

经过上面的学习,那我们基于socket服务端的十几行代码写一个我们自己的web框架。我们先不处理浏览器发送的请求,先让浏览器能显示我们web框架返回的信息,那我们就要按照HTTP协议的格式来发送响应。

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

我们通过十几行代码简单地演示了web 框架的本质。

接下来就让我们继续完善我们的自定义web框架吧!

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

这样就结束了吗? 如何让我们的Web服务根据用户请求的URL不同而返回不同的内容呢?

小事一桩,我们可以从请求相关数据里面拿到请求URL的路径,然后拿路径做一个判断...

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

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

上面的代码解决了不同URL路径返回不同内容的需求。

我们返回的内容是简单的几个字符,那如果我可以将返回的结果封装成一个函数呢?

  1. """
  2. 根据URL中不同的路径返回不同的内容--函数版
  3. """
  4. import socket
  5. sk = socket.socket()
  6. sk.bind(("127.0.0.1", 8080))  # 绑定IP和端口
  7. sk.listen()  # 监听
  8. # 将返回不同的内容部分封装成函数
  9. def func(url):
  10. s = "这是{}页面!".format(url)
  11. return bytes(s, encoding="utf8")
  12. while True:
  13. # 等待连接
  14. conn, add = sk.accept()
  15. data = conn.recv(8096)  # 接收客户端发来的消息
  16. # 从data中取到路径
  17. data = str(data, encoding="utf8")  # 把收到的字节类型的数据转换成字符串
  18. # 按\r\n分割
  19. data1 = data.split("\r\n")[0]
  20. url = data1.split()[1]  # url是我们从浏览器发过来的消息中分离出的访问路径
  21. conn.send(b'HTTP/1.1 200 OK\r\n\r\n')  # 因为要遵循HTTP协议,所以回复的消息也要加状态行
  22. # 根据不同的路径返回不同内容,response是具体的响应体
  23. if url == "/index/":
  24. response = func(url)
  25. elif url == "/home/":
  26. response = func(url)
  27. else:
  28. response = b"404 not found!"
  29. conn.send(response)
  30. conn.close()

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

看起来上面的代码写了一个函数,那肯定可以写多个函数,不同的路径对应执行不同的函数拿到结果,但是我们要一个个判断路径,是不是很麻烦?我们有简单的办法来解决。

  1. """
  2. 根据URL中不同的路径返回不同的内容--函数进阶版
  3. """
  4. import socket
  5. sk = socket.socket()
  6. sk.bind(("127.0.0.1", 8080))  # 绑定IP和端口
  7. sk.listen()  # 监听
  8. # 将返回不同的内容部分封装成不同的函数
  9. def index(url):
  10. s = "这是{}页面XX!".format(url)
  11. return bytes(s, encoding="utf8")
  12. def home(url):
  13. s = "这是{}页面。。!".format(url)
  14. return bytes(s, encoding="utf8")
  15. # 定义一个url和实际要执行的函数的对应关系
  16. list1 = [
  17. ("/index/", index),
  18. ("/home/", home),
  19. ]
  20. while True:
  21. # 等待连接
  22. conn, add = sk.accept()
  23. data = conn.recv(8096)  # 接收客户端发来的消息
  24. # 从data中取到路径
  25. data = str(data, encoding="utf8")  # 把收到的字节类型的数据转换成字符串
  26. # 按\r\n分割
  27. data1 = data.split("\r\n")[0]
  28. url = data1.split()[1]  # url是我们从浏览器发过来的消息中分离出的访问路径
  29. conn.send(b'HTTP/1.1 200 OK\r\n\r\n')  # 因为要遵循HTTP协议,所以回复的消息也要加状态行
  30. # 根据不同的路径返回不同内容
  31. func = None  # 定义一个保存将要执行的函数名的变量
  32. for item in list1:
  33. if item[0] == url:
  34. func = item[1]
  35. break
  36. if func:
  37. response = func(url)
  38. else:
  39. response = b"404 not found!"
  40. # 返回具体的响应消息
  41. conn.send(response)
  42. conn.close()

返回具体的HTML文件

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

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

  1. """
  2. 根据URL中不同的路径返回不同的内容--函数进阶版
  3. 返回独立的HTML页面
  4. """
  5. import socket
  6. sk = socket.socket()
  7. sk.bind(("127.0.0.1", 8080))  # 绑定IP和端口
  8. sk.listen()  # 监听
  9. # 将返回不同的内容部分封装成不同的函数
  10. def index(url):
  11. # 读取index.html页面的内容
  12. with open("index.html", "r", encoding="utf8") as f:
  13. s = f.read()
  14. # 返回字节数据
  15. return bytes(s, encoding="utf8")
  16. def home(url):
  17. with open("home.html", "r", encoding="utf8") as f:
  18. s = f.read()
  19. return bytes(s, encoding="utf8")
  20. # 定义一个url和实际要执行的函数的对应关系
  21. list1 = [
  22. ("/index/", index),
  23. ("/home/", home),
  24. ]
  25. while True:
  26. # 等待连接
  27. conn, add = sk.accept()
  28. data = conn.recv(8096)  # 接收客户端发来的消息
  29. # 从data中取到路径
  30. data = str(data, encoding="utf8")  # 把收到的字节类型的数据转换成字符串
  31. # 按\r\n分割
  32. data1 = data.split("\r\n")[0]
  33. url = data1.split()[1]  # url是我们从浏览器发过来的消息中分离出的访问路径
  34. conn.send(b'HTTP/1.1 200 OK\r\n\r\n')  # 因为要遵循HTTP协议,所以回复的消息也要加状态行
  35. # 根据不同的路径返回不同内容
  36. func = None  # 定义一个保存将要执行的函数名的变量
  37. for item in list1:
  38. if item[0] == url:
  39. func = item[1]
  40. break
  41. if func:
  42. response = func(url)
  43. else:
  44. response = b"404 not found!"
  45. # 返回具体的响应消息
  46. conn.send(response)
  47. conn.close()
<!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>index</title>
</head>
<body>
<div>这是index页面</div>
</body>
</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>index</title>
</head>
<body>
<div>这是home页面</div>
</body>
</html>

让网页动态起来

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

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

  1. """
  2. 根据URL中不同的路径返回不同的内容--函数进阶版
  3. 返回独立的HTML页面
  4. """
  5. import socket
  6. sk = socket.socket()
  7. sk.bind(("127.0.0.1", 8080))  # 绑定IP和端口
  8. sk.listen()  # 监听
  9. # 将返回不同的内容部分封装成不同的函数
  10. def index(url):
  11. # 读取index.html页面的内容
  12. with open("index.html", "r", encoding="utf8") as f:
  13. s = f.read()
  14. # 返回字节数据
  15. return bytes(s, encoding="utf8")
  16. def home(url):
  17. with open("home.html", "r", encoding="utf8") as f:
  18. s = f.read()
  19. return bytes(s, encoding="utf8")
  20. def timer(url):
  21. import time
  22. with open("time.html", "r", encoding="utf8") as f:
  23. s = f.read()
  24. s = s.replace('@@time@@', time.strftime("%Y-%m-%d %H:%M:%S"))
  25. return bytes(s, encoding="utf8")
  26. # 定义一个url和实际要执行的函数的对应关系
  27. list1 = [
  28. ("/index/", index),
  29. ("/home/", home),
  30. ("/time/", timer),
  31. ]
  32. while True:
  33. # 等待连接
  34. conn, add = sk.accept()
  35. data = conn.recv(8096)  # 接收客户端发来的消息
  36. # 从data中取到路径
  37. data = str(data, encoding="utf8")  # 把收到的字节类型的数据转换成字符串
  38. # 按\r\n分割
  39. data1 = data.split("\r\n")[0]
  40. url = data1.split()[1]  # url是我们从浏览器发过来的消息中分离出的访问路径
  41. conn.send(b'HTTP/1.1 200 OK\r\n\r\n')  # 因为要遵循HTTP协议,所以回复的消息也要加状态行
  42. # 根据不同的路径返回不同内容
  43. func = None  # 定义一个保存将要执行的函数名的变量
  44. for item in list1:
  45. if item[0] == url:
  46. func = item[1]
  47. break
  48. if func:
  49. response = func(url)
  50. else:
  51. response = b"404 not found!"
  52. # 返回具体的响应消息
  53. conn.send(response)
  54. 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部分:

  1. """
  2. 根据URL中不同的路径返回不同的内容--函数进阶版
  3. 返回HTML页面
  4. 让网页动态起来
  5. wsgiref模块版
  6. """
  7. from wsgiref.simple_server import make_server
  8. # 将返回不同的内容部分封装成函数
  9. def index(url):
  10. # 读取index.html页面的内容
  11. with open("index.html", "r", encoding="utf8") as f:
  12. s = f.read()
  13. # 返回字节数据
  14. return bytes(s, encoding="utf8")
  15. def home(url):
  16. with open("home.html", "r", encoding="utf8") as f:
  17. s = f.read()
  18. return bytes(s, encoding="utf8")
  19. def timer(url):
  20. import time
  21. with open("time.html", "r", encoding="utf8") as f:
  22. s = f.read()
  23. s = s.replace('@@time@@', time.strftime("%Y-%m-%d %H:%M:%S"))
  24. return bytes(s, encoding="utf8")
  25. # 定义一个url和实际要执行的函数的对应关系
  26. list1 = [
  27. ("/index/", index),
  28. ("/home/", home),
  29. ("/time/", timer),
  30. ]
  31. def run_server(environ, start_response):
  32. start_response('200 OK', [('Content-Type', 'text/html;charset=utf8'), ])  # 设置HTTP响应的状态码和头信息
  33. url = environ['PATH_INFO']  # 取到用户输入的url
  34. func = None
  35. for i in list1:
  36. if i[0] == url:
  37. func = i[1]
  38. break
  39. if func:
  40. response = func(url)
  41. else:
  42. response = b"404 not found!"
  43. return [response, ]
  44. if __name__ == '__main__':
  45. httpd = make_server('127.0.0.1', 8090, run_server)
  46. print("我在8090等你哦...")
  47. httpd.serve_forever()

jinja2

上面的代码实现了一个简单的动态,我完全可以从数据库中查询数据,然后去替换我html中的对应内容,然后再发送给浏览器完成渲染。 这个过程就相当于HTML模板渲染数据。 本质上就是HTML内容中利用一些特殊的符号来替换要展示的数据。 我这里用的特殊符号是我定义的,其实模板渲染有个现成的工具: jinja2

下载jinja2:

pip install jinja2
<!DOCTYPE html>
<html lang="zh-CN">
<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>
<h1>姓名:{{name}}</h1>
<h1>爱好:</h1>
<ul>
{% for hobby in hobby_list %}
<li>{{hobby}}</li>
{% endfor %}
</ul>
</body>
</html>

使用jinja2渲染index2.html文件:

  1. from wsgiref.simple_server import make_server
  2. from jinja2 import Template
  3. def index(url):
  4. # 读取HTML文件内容
  5. with open("index2.html", "r", encoding="utf8") as f:
  6. data = f.read()
  7. template = Template(data)   # 生成模板文件
  8. ret = template.render({'name': 'alex', 'hobby_list': ['抽烟', '喝酒', '烫头']})   # 把数据填充到模板中
  9. return bytes(ret, encoding="utf8")
  10. def home(url):
  11. with open("home.html", "r", encoding="utf8") as f:
  12. s = f.read()
  13. return bytes(s, encoding="utf8")
  14. # 定义一个url和实际要执行的函数的对应关系
  15. list1 = [
  16. ("/index/", index),
  17. ("/home/", home),
  18. ]
  19. def run_server(environ, start_response):
  20. start_response('200 OK', [('Content-Type', 'text/html;charset=utf8'), ])  # 设置HTTP响应的状态码和头信息
  21. url = environ['PATH_INFO']  # 取到用户输入的url
  22. func = None
  23. for i in list1:
  24. if i[0] == url:
  25. func = i[1]
  26. break
  27. if func:
  28. response = func(url)
  29. else:
  30. response = b"404 not found!"
  31. return [response, ]
  32. if __name__ == '__main__':
  33. httpd = make_server('127.0.0.1', 8090, run_server)
  34. print("我在8090等你哦...")
  35. httpd.serve_forever()

现在的数据是我们自己手写的,那可不可以从数据库中查询数据,来填充页面呢?

使用pymysql连接数据库:

conn = pymysql.connect(host="127.0.0.1", port=3306, user="root", passwd="xxx", db="xxx", charset="utf8")
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
cursor.execute("select name, age, department_id from userinfo")
user_list = cursor.fetchall()
cursor.close()
conn.close()

创建一个测试的user表:

CREATE TABLE user(
id int auto_increment PRIMARY KEY,
name CHAR(10) NOT NULL,
hobby CHAR(20) NOT NULL
)engine=innodb DEFAULT charset=UTF8;

模板的原理就是字符串替换,我们只要在HTML页面中遵循jinja2的语法规则写上,其内部就会按照指定的语法进行相应的替换,从而达到动态的返回内容。

Django

Django官网下载页面

安装(安装最新LTS版):

pip3 install django==1.11.15

创建一个django项目:

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

django-admin startproject mysite

目录介绍:

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

运行Django项目:

python manage.py runserver 127.0.0.1:8000

模板文件配置:

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

静态文件配置:

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

看不明白?有图有真相:

刚开始学习时可在配置文件中暂时禁用csrf中间件,方便表单提交测试。

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

Django基础必备三件套:

from django.shortcuts import HttpResponse, render, redirect

HttpResponse

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

例如:

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

render

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

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

例如:

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

redirect

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

例如:

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

重定向是怎么回事?

启动Django报错:

Django 启动时报错 UnicodeEncodeError ...

报这个错误通常是因为计算机名为中文,改成英文的计算机名重启下电脑就可以了。

Django _web框架本质的更多相关文章

  1. Django:web框架本质

    一,web框架本质 我们可以这样理解:所有的Web应用本质上就是一个socket服务端,而用户的浏览器就是一个socket客户端. 这样我们就可以自己实现Web框架了. 1,自定义web框架 impo ...

  2. [oldboy-django][1初始django]web框架本质 + django框架 + ajax

    web框架本质 浏览器(socket客户端) - 发送请求(ip和端口,url http://www.baidu.com:80/index/) - GET 请求头(数据请求行的url上: Http1. ...

  3. Web框架本质及第一个Django实例

    Web框架本质 我们可以这样理解:所有的Web应用本质上就是一个socket服务端,而用户的浏览器就是一个socket客户端. 这样我们就可以自己实现Web框架了. 半成品自定义web框架 impor ...

  4. Web框架本质及第一个Django实例 Web框架

    Web框架本质及第一个Django实例   Web框架本质 我们可以这样理解:所有的Web应用本质上就是一个socket服务端,而用户的浏览器就是一个socket客户端. 这样我们就可以自己实现Web ...

  5. WEB框架本质和第一个Django实例

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

  6. Django之Web框架本质及第一个Django实例

    Web框架本质 我们可以这样理解:所有的Web应用本质上就是一个socket服务端,而用户的浏览器就是一个socket客户端. 这样我们就可以自己实现Web框架了. 半成品自定义web框架 impor ...

  7. Django框架----Web框架本质

    Web框架本质 我们可以这样理解:所有的Web应用本质上就是一个socket服务端,而用户的浏览器就是一个socket客户端. 这样我们就可以自己实现Web框架了. 半成品自定义web框架 impor ...

  8. Django 基础 web框架本质

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

  9. DAY15-web框架本质及第一个Django实例

    Web框架本质 我们可以这样理解:所有的Web应用本质上就是一个socket服务端,而用户的浏览器就是一个socket客户端. 这样我们就可以自己实现Web框架了. 半成品自定义web框架 impor ...

随机推荐

  1. 微软科学家Leslie Lamport荣获2013年图灵奖

    Lamport荣获2013年图灵奖" title="微软科学家Leslie Lamport荣获2013年图灵奖"> 编者按:Leslie Lamport,新晋图灵奖 ...

  2. python学习笔记(8)迭代器和生成器

    迭代器 迭代是Python最强大的功能之一,是访问集合元素的一种方式. 迭代器是一个可以记住遍历的位置的对象. 迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束.迭代器只能往前不会后退 ...

  3. yum命令不能使用的解决办法

    以前yum命令一直是可用的,今天使用它安装命令时一直提示,如下图: 百度了一圈说是网络问题: 然后我就ping www.baidu.com  可以ping通啊 最后在同事的帮助下找到了解决办法: vi ...

  4. springdatajpa 认识以及使用方式

    1.spingdatajpa是什么? Spring Data JPA 是 Spring 基于 ORM 框架.JPA 规范的基础上封装的一套JPA应用框架(即上述的:JPA的实现产品),可使开发者用极简 ...

  5. jenkins邮件内容模板

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  6. Ionic3学习笔记(十三)HttpClient 实现 HTTP 请求以及踩过的一些坑

    本文为原创文章,转载请标明出处 目录 猫眼API HttpClient 实现 HTTP 请求 安装 HttpClientModule 模块 创建 provider 创建 page 一些坑 坑1: 未在 ...

  7. ajax async异步

    async默认的设置值为true,这种情况为异步方式,就是说当ajax发送请求后,在等待server端返回的这个过程中,前台会继续执行ajax块后面的脚本,直到server端返回正确的结果才会去执行s ...

  8. 在dataframe添加1行(首行,或者尾部),且不覆盖

    如果直接用下面的代码添加第1行,则会覆盖掉原来的第1行. #指定位置增加一行: df.loc[0]={'a':1,'b':2} 正确方法: 新建一个同样的 dataframe, 然后合并两个dataf ...

  9. Oracle Compute云快速搭建MySQL Keepalived高可用架构

    最近有个客户在测试Oracle Compute云,他们的应用需要使用MySQL数据库,由于是企业级应用一定要考虑高可用架构,因此有需求要在Oracle Compute云上搭建MySQL高可用集群.客户 ...

  10. C轮魔咒:智能硬件为什么融资难

    据相关媒体不完全统计,2015年完成融资的智能硬件公司集中在A轮和B轮,但能挺进C轮的少之又少.对智能硬件创业的年终盘点也显示,此前比较热门的手环.智能家居等主要单品在去年明显出现了回落.陷入C轮魔咒 ...