目录
1.HTTP协议
2.HTTP请求头
3.IP地址的绑定
4.根据不同的请求返回不同的内容
5.面向对象的服务器封装
6.WSGI服务器
6.1 WSGI接口
6.2 WSGI不同路径返回不同内容
6.3 读取文件并加载返回给浏览器
6.4 方法的封装
6.5 requests模块的使用
HTTP协议:HyperText Transfer Protocol 超文本传输协议
协议的作用:就是用来传输超文本(HTML:HyperTextMarkupLanguage超文本标记语言)HTML:超文本标记语言
HTTP:用来传输超文本的一个协议
C/S架构:client-server 手机淘宝APP
B/S架构:browser-server 浏览器访问淘宝
在Web应用中,服务器把网页传给浏览器,实际上就是把网页的HTML代码发送给浏览器,让浏览器显示出来。而浏览器和服务器之间的传输协议是HTTP,所以:
- HTML是一种用来定义网页的文本,会HTML,就可以编写网页;
- HTTP是在网络上传输HTML的协议,用于浏览器和服务器的通信。
Chrome浏览器提供了一套完整地调试工具,非常适合Web开发。
安装好Chrome浏览器后,打开Chrome,在菜单中选择“视图”,“开发者",“开发者工具”,就可以显示开发者工具。
import socket
port=int(input('请输入端口号:'))
n=int(input('请输入您允许访问该网站的次数:'))
#HTTP 服务器都是基于TCP的socket连接
server_socket=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
server_socket.bind(('192.168.1.223',port))
server_socket.listen(128)
print('server is running ar 192.168.1.223:{}'.format(port))
#获取到数据时一个元组
#第0个元素:客户端的socket连接
#第1个元素:客户端的ip和端口号
while n:
n-=1
client_socket,client_addr=server_socket.accept()
#从客户端的socket中获取数据
data=client_socket.recv(1024)
print('接收到了来自{}地址{}端口号的的信息,内容是:{}'.format(client_addr[0],client_addr[1],data.decode('gbk')))
#在返回内容之前需要设置HTTP响应头
#设置一个响应头就换一行
client_socket.send('HTTP/1.1 200 OK\n'.encode('gbk'))
client_socket.send('content-type:text/html\n'.encode('gbk'))
#所有的响应头设置完成后再换行
client_socket.send('\n'.encode('gbk'))
#给客户端的返回消息
client_socket.send(client_addr[0].encode('gbk'))
运行结果:
"""
#GET 请求方式,GET/POST/PUT/DELETE...
#/index.html 请求的路径
#HTTP/1.1 HTTP的版本号
GET / HTTP/1.1
Host: 192.168.1.223:8080 #客户端请求的服务器地址
Connection: keep-alive
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
#UA 用户代理,设计目的是为了能从请求头里辨识浏览器的类型
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.66 Safari/537.36 Edg/103.0.1264.44
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
"""
#IP地址能够通过IP地址访问
#server_socket.bind(('192.168.1.223', 8080))
#能够通过127.0.0.1 和localhost(只有局域网内的主机才可以访问) 来访问
#127.0.0.1 和0.0.0.0都表示本机 0.0.0.0表示所有的可用的地址
server_socket.bind(('127.0.0.1', 8080))
import socket
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.bind(('127.0.0.1', 8080))
server_socket.listen(128)
print('server is running ar 192.168.1.223:{}'.format(8080))
while True:
client_socket, client_addr = server_socket.accept()
data = client_socket.recv(1024).decode('gbk')#浏览器发送的数据有可能是空的
#print('接收到了来自{}地址{}端口号的的信息,内容是:{}'.format(client_addr[0], client_addr[1], data))
path = ''
if data:
path=data.splitlines()[0].split()[1]#切字符串
print('请求的路径是:{}'.format(path))
# 响应体
response_body = 'hello zmj!'
# 响应头
response_header = 'HTTP/1.1 200 OK\n' # 200是OK状态码
if path=='/login':
response_body='欢迎来到登录页面!'
elif path=='/register':
response_body='欢迎来到注册页面'
elif path=='/':
response_body='欢迎来到首页'
else:
#页面没找到 404 Page Not Found
response_header = 'HTTP/1.1 404 Page Not Found\n' # 200是OK状态码
response_body='对不起,您要查找的页面不存在!!!'
response_header+='content-type:text/html;charset=utf8\n'
response_header+='\n'
#响应
response=response_header+response_body
#发送给客户端
client_socket.send(response.encode('utf8'))
运行结果:
import socket
class MyServer(object):
def __init__(self,ip,port):
self.socket=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
self.socket.bind((ip,port))
self.socket.listen(128)
def run_forever(self):
while True:
client_socket, client_addr = self.socket.accept()
data = client_socket.recv(1024).decode('gbk')
path = ''
if data:
path = data.splitlines()[0].split()[1] # 切字符串
response_body = 'hello zmj!'
response_header = 'HTTP/1.1 200 OK\n' # 200是OK状态码
if path == '/login':
response_body = '欢迎来到登录页面!'
elif path == '/register':
response_body = '欢迎来到注册页面'
elif path == '/':
response_body = '欢迎来到首页'
else:
response_header = 'HTTP/1.1 404 Page Not Found\n' # 200是OK状态码
response_body = '对不起,您要查找的页面不存在!!!'
response_header += 'content-type:text/html;charset=utf8\n'
response_header += '\n'
response = response_header + response_body
client_socket.send(response.encode('utf8'))
server=MyServer('127.0.0.1',8080)
server.run_forever()
WSGI接口定义非常简单,它只要求Web开发者实现一个函数,就可以响应HTTP请求。我们来看一个最简单的Web版本的“Hello, web!”:
def application(environ,start_response):
start_response('200 OK',[('Content-Type','text/html')]
return 'Hello,web!
'
上面的application()函数就是符合WSGI标准的一个HTTL处理函数,它接收两个参数:
- environ:一个包含所有的HTTL请求信息的dict对象;
- start_response:一个发送HTTP响应的函数
在application()函数中调用:start_response('200 OK',[('Content-Type','text/html')],就发送了HTTP响应的Header,注意Header只能发送一次,也就是只能调用一次start_response()函数。start_response()函数调用两个参数,一个是HTTP响应码,一个是一组list表示的HTTP Header,每个Header用一个包含两个str的tuple表示。
通常情况下,都应该把Content-Type头发送给浏览器,其他很多常用的HTTP Header也应该发送。
代码一:
#直接使用库里面的
import webbrowser
from wsgiref.simple_server import make_server, demo_app
if __name__=='__main__':
httpd=make_server('',8000,demo_app)
sa=httpd.socket.getsockname()
print('Serving HTTP on',sa[0],'port',sa[1],'...')
webbrowser.open('http://localhost:8000/xyz?abc')
httpd.serve_forever()
结果:
代码二:
#自定义显示内容
import webbrowser
from wsgiref.simple_server import make_server
#demo_app需要两个参数,
#第1个参数:表示环境(电脑的环境;请求路径的相关的环境)
#第2个参数:是一个函数,用于返回响应头
#需要返回值,返回值是一个列表,列表中只有一个元素,是一个二进制,表示返回给浏览器的数据
def demo_app(environ,start_response):
#environ 是一个字典,保存了很多数据
#其中重要的一个是PATH_INFO能够获取到用户的访问路径
path=environ['PATH_INFO']
print('path={}'.format(path))
#start_response第一个参数是状态码,第二个是响应头
start_response('200 OK',[('Content-Type','text/html;charset=utf8')])
return ['hello'.encode('utf8')]#浏览器显示的内容
if __name__=='__main__':
#demo_app是一个函数,用来处理用户的请求
#8000是一个端口号
httpd=make_server('',8000,demo_app)
sa=httpd.socket.getsockname()
print('Serving HTTP on',sa[0],'port',sa[1],'...')
#作用:打开电脑的浏览器,并在浏览器中输入'http://localhost:8000/xyz?abc'
#也可以手动打开
webbrowser.open('http://localhost:8000/xyz?abc')
# 只处理一个请求,然后退出
#httpd.handle_request()
httpd.serve_forever()#服务器在后台一直运行
结果:
# 状态码:RSETFUL ==>前后端分离
# 2XX:请求响应成功
# 3XX:重定向
# 4XX:客户端的错误。 404:客户端访问了一个不存在的地址 405:请求方式不被允许
# 5XX:服务器的错误。
import webbrowser
from wsgiref.simple_server import make_server
#demo_app需要两个参数,
#第1个参数:表示环境(电脑的环境;请求路径的相关的环境)
#第2个参数:是一个函数,用于返回响应头
#需要返回值,返回值是一个列表,列表中只有一个元素,是一个二进制,表示返回给浏览器的数据
def demo_app(environ,start_response):
#environ 是一个字典,保存了很多数据
#其中重要的一个是PATH_INFO能够获取到用户的访问路径
path=environ['PATH_INFO']
status_code='200 OK'#默认状态码是200
if path=='/':
response='欢迎来到我的首页'
elif path=='/text':
response='欢迎来到张梦姣的页面'
elif path=='/demo':
response='欢迎来到demo页面'
else:
response='页面走丢了!'#如果页面出问题了,
status_code='404 Not Found'
#start_response第一个参数是状态码,第二个是响应头
start_response(status_code,[('Content-Type','text/html;charset=utf8')])
return [response.encode('utf8')]#浏览器显示的内容
if __name__=='__main__':
#demo_app是一个函数,用来处理用户的请求
#8000是一个端口号
httpd=make_server('127.0.0.1',8080,demo_app)#这里第一个参数是地址,空表示是'0.0.0.0'
sa=httpd.socket.getsockname()
print('Serving HTTP on',sa[0],'port',sa[1],'...')
#作用:打开电脑的浏览器,并在浏览器中输入'http://localhost:8000/xyz?abc'
#也可以手动打开
#webbrowser.open('http://localhost:8000/xyz?abc')
# 只处理一个请求,然后退出
#httpd.handle_request()
httpd.serve_forever()#服务器在后台一直运行
去掉注释的代码:
import webbrowser
from wsgiref.simple_server import make_server
def demo_app(environ,start_response):
path=environ['PATH_INFO']
status_code='200 OK'#默认状态码是200
if path=='/':
response='欢迎来到我的首页'
elif path=='/text':
response='欢迎来到张梦姣的页面'
elif path=='/demo':
response='欢迎来到demo页面'
else:
response='页面走丢了!'#如果页面出问题了,
status_code='404 Not Found'
start_response(status_code,[('Content-Type','text/html;charset=utf8')])
return [response.encode('utf8')]
if __name__=='__main__':
httpd=make_server('127.0.0.1',8080,demo_app)
sa=httpd.socket.getsockname()
print('Serving HTTP on',sa[0],'port',sa[1],'...')
httpd.serve_forever()
结果:
import json
import webbrowser
from wsgiref.simple_server import make_server
def demo_app(environ,start_response):
path=environ['PATH_INFO']
#print(environ.get('QUERY_STRING'))#query_string ==>获取到客户端GET请求方式传递的参数
status_code='200 OK'
if path=='/':
response='欢迎来到我的首页'
elif path=='/test':
response=json.dumps({'name':'zhangsan','age':20,'gender':'male'})
elif path=='/demo':
with open('./pages/xxxx.txt','r',encoding='utf8') as file:
response = file.read()
elif path=='/hello':
with open('./pages/hello.html', 'r', encoding='utf8') as file:
response = file.read()
elif path=='/info':
#查找数据库,获取到用户名
name='Tom'
with open('./pages/info.html', 'r', encoding='utf8') as file:
#flash django 模板,渲染引擎
response = file.read().format(username=name)#读取的就是字符串
else:
response='页面走丢了!'#如果页面出问题了,
status_code='404 Not Found'
#start_response第一个参数是状态码,第二个是响应头
start_response(status_code,[('Content-Type','text/html;charset=utf8')])
return [response.encode('utf8')]#浏览器显示的内容
if __name__=='__main__':
httpd=make_server('127.0.0.1',8080,demo_app)
sa=httpd.socket.getsockname()
print('Serving HTTP on',sa[0],'port',sa[1],'...')
httpd.serve_forever()#服务器在后台一直运行
hello.html文件里面的内容:
Title
info.html文件里面的内容:
Title
{username},欢迎回来,
前端结果:
import json
import webbrowser
from wsgiref.simple_server import make_server
def load_html(file_name):
try:
with open('./pages/'+file_name,'r',encoding='utf8') as file:
content=file.read()
return content
except FileNotFoundError:
print(file_name,'文件没找到!')
def index():
return '欢迎来到我的首页'
def show_test():
return json.dumps({'name':'zhangsan','age':20,'gender':'male'})
def show_demo():
return load_html('xxxx.txt')
def show_hello():
return load_html('hello.html')
def show_info():
# 查找数据库,获取到用户名
name = 'Tom'
return load_html('info.html').format(username=name)
url={'/':index,
'/test':show_test,
'/demo':show_demo,
'/info':show_info,
'/hello':show_hello()
}
def demo_app(environ,start_response):
path=environ['PATH_INFO']
status_code='200 OK'
method=url.get(path)
if method:
response=method()
else:
response = '页面走丢了!' # 如果页面出问题了,
status_code = '404 Not Found'
start_response(status_code,[('Content-Type','text/html;charset=utf8')])
return [response.encode('utf8')]
if __name__=='__main__':
httpd=make_server('127.0.0.1',8000,demo_app)
sa=httpd.socket.getsockname()
print('Serving HTTP on',sa[0],'port',sa[1],'...')
httpd.serve_forever()
作用就是模拟浏览器,获取请求的功能。
#requests模块是第三方的模块,可以用来发送网络连接
import requests
response=requests.get('http://127.0.0.1:8000')#注意:这个路径需要写http
print(response)# ==> 结果是一个Response对象
print(response.content.decode('utf8'))#"欢迎来到我的首页" ==> 获取的内容,返回的是一个二进制(可以用来传递图片),需要decode
print(response.text,' 类型:',type(response.text))#'欢迎来到我的首页' ==> 结果就是字符串,不需要decode
print(response.status_code)#200 ==> 获取状态码
#若果返回的结果是json串,就用这个解析
#print(response.json())#json的返回类型不是字符串,而是原数据类型
运行结果: