49web开发1_http_wsgiref
灵山ssl适用于网站、小程序/APP、API接口等需要进行数据传输应用场景,ssl证书未来市场广阔!成为创新互联建站的ssl证书销售渠道,可以享受市场价格4-6折优惠!如果有意向欢迎电话联系或者加微信:028-86922220(备注:SSL证书合作)期待与您的合作!
目录
cs和bs:... 1
http协议:... 2
http消息:... 3
Request:... 3
常见传递信息的方式:... 3
Response:... 4
wsgi:... 5
wsgi app应用程序端:... 6
wsgi server服务器端:... 7
测试用命令:... 9
QUERY_STRING查询字符串解析:... 9
web开发:
cs和bs:
c和s之间需使用socket,约定协议、版本(往往使用tcp、udp),指定地址和端口,就可以通信;
c和s传输数据,数据可以有一定的格式,双方必须先约定好;
b和s:
b,一种特殊client,支持http(s)协议,能通过url向服务器发起请求,等待服务器端返回html等数据,并在browser内可视化展示的程序;
s,支持http(s),能接受众多客户端发起的http协议请求,经过处理,将html等数据返回给b;
本质上,bs是一种特殊的cs:
即客户端必须是一种支持http协议且能解析并渲染html的软件;
服务端必须是能接收多客户端的http访问的服务器软件;
客户端开发或前端开发;
服务端开发,py可学wsgi、django、flask、tornado等;
py,web框架:
早期cgi;
wsgi,web server gateway interface,可看作是一种底层协议,它规定了服务器程序和应用程序各自实现什么接口,py的实现为wsgiref库;
flask,基于wsgi,微框架;
django,基于wsgi,开源的web框架,巨无霸;
http协议:
是无状态的、面向连接的协议;
无状态,同一个客户端的两次请求,从服务端角度来说,它并不知道这两个请求来自同一个客户端;
解决:通过cookie(session或token)来判断;
面向连接:
有连接,基于tcp是面向连接,需3次握手4次断开;
短连接:http1.0是一个请求一个连接,而tcp创建销毁成本高,对server有很大影响;http1.1,支持keep-alive,默认开启,一个连接打开后会保持一段时间(可设置),b再访问该s就使用这个tcp连接,减轻了服务器压力,提高了效率;
cookie:
为解决http的无状态,用到cookie(sessionID或token);
一般,cookie信息是服务端生成,返回给客户端的;
客户端可自己设置cookie信息;
键值对信息,有时效;
browser发起每一个请求时,都会把cookie信息发给服务端;
是一种客户端、服务端传递数据的技术;
服务端可通过判断这些信息,来确定这次请求是否和之前的请求有关联,服务端为了认识同一个client,用sessionID或token,sessionID、token可理解为是一种标识,这些标识要么通过cookie带,要么通过url带,要么通过request body带;
注:
sessionID,保存在服务端内存中,随着会话关闭而消亡;
token,替代sessionID,server发给client的令牌,server通过此标识来认client;
url组成:
uniform resource locator统一资源定位符,每一个链接指向一个资源供客户端访问;
schema://host[:port#]/path/.../[;url-params][?query-string][#anchor]
schema,模式、协议,http、ftp、file、mailto、MySQL等;
host:port,80默认可不写,有域名解析,实际上应该是IP;
/path/to/resource,path指向资源的路径;
?key1=value1&key2=value2,query string查询字符串,问号分割,后面key=value形式且用&分割;
http消息:
分为Request、Response,请求和响应都由请求消息行(请求行)、header消息报头、body消息正文组成;
Request:
request method请求方法:
GET,请求获取url对应的资源;
POST,提交数据至服务器端;
HEAD,和GET类似,不过不返回消息正文;
例:
GET / HTTP/1.1 #请求行,分别为:请求方法 请求路径 协议版本CRLF,CRLF为回车换行
Host:
User-Agent:
Accept:
Accept-Language:
Accept-Encoding:
Cookie:
Connection:
Upgrade-Insecure-Requests: #header消息报头
body: #两个CRLF后是body
常见传递信息的方式:
1、GET方法使用query string:
例:
http://www.magedu.com/python/index.html?id=5&name=python
2、POST方法提交数据:
例:
http://127.0.0.1:9999/xxx/yyy?id=5&name=python
使用表单提交数据,文本框name为age、weigth、height
请求消息如下:
POST /xxx/yyy?id=5name=python HTTP/1.1
HOST: 127.0.0.1:9999
content-length: 26
content-type: application/x-www-form-urlencoded
age=5&wegith=80&height=170
3、url中本身就包含着信息:
http://www.magedu.com/python/student/001
注:
ajax就是用以上3种方式传输的,不过是异步方式;
客户端传参的几种方式:
1、通过URL路径传递,如http://ip:port/news/1/2,两个参数,新闻类型id和页码;
2、通过query string传递,如http://ip:port/news?category=1&page=2;
3、通过body请求体传递,又可根据数据格式分为k-v对、form数据、非form数据(json|xml);
4、通过http header传递;
Response:
例:
HTTP/1.1 200 OK #响应消息行,依次为:协议版本 状态码 Message
status code状态码:
1XX,提示信息,表示请求已被成功接收,继续处理;
2XX,表示正常响应;
200,正常返回了网页内容;
201,Created;
3XX,重定向;
301,页面永久性移走,永久重定向,返回新的url,b会根据返回的url发起新的request请求;
302,临时重定向;
304,资源未修改,b使用本地缓存;
4XX,客户端请求错误;
404,Not Found,网页找不到;
400,请求语法错误;
401,请求要求身份验证;
403,服务器拒绝请求;
5XX,服务器端错误;
500,服务器内部错误;
502,上游服务器错误,如nginx反向代理时;
例,编写类flask框架:
使用wsgi开发框架;
目的:
学习web框架的工作机制,了解众多框架背后的技术;
学习API封装,学习框架封装的思想,并提供友好的编程接口;
注:
一般公司会直接使用类似于django这样的框架,但一旦代码规模到了一定阶段,就需要对框架作二次开发,定制改版,所以了解框架背后的技术非常重要;
wsgi:
wsgi,规定了服务器端和应用程序之间的接口;
请求、响应的数据都要经wsgi server转发;
wsgi app看不到是哪个socket建立的连接(除非改wsgi接口);
wsgi app应用程序端:
1、应是一个可调用对象,py中应是函数、类、实现了__call__方法的类的实例;
2、这个可调用对象应接收2个参数,如
def application(environ,start_response): #函数实现
return [res_str]
class Application: #类实现
def __init__(self,environ,start_response):
pass
def __iter__(self):
yield res_str
class Application: #类实现
def __call__(self,environ,start_response):
return [res_str]
3、以上三种实现(三种都有用,框架简单用函数,框架复杂用类多些,更复杂都用),必须返回一个可迭代对象;
environ、start_response参数:
这两个参数可以是任何合法名,一般默认用这两个名字;
environ,是包含http请求信息的dict对象:
REQUEST_METHOD #请求方法,GET、POST等
PATH_INFO #url中的路径部分
QUERY_STRING #查询字符串
SERVER_NAME,SERVER_PORT
HTTP_HOST #IP:PORT
SERVER_PROTOCOL #协议
HTTP_USER_AGENT #UserAgent信息,对互联网公司非常重要,可对用户作精准分析
start_response是一个可调用对象,有3个参数:
start_response(status,response_headers,exc_info=None) #start_response应在返回可迭代对象前调用,因为它返回的是response header,而application返回的可迭代对象response body
status #状态码
response_headers #是一个元素为二元组列表,如[('Content-Type','text/plain;charset=utf-8')],用二元组模拟字典
exc_info #在错误处理时用
注:
'text/plain;charset=utf-8'
'text/html;charset=utf-8' #对中文开发,此处要通知browser使用的编码,browser只认此处的通知,以让b达到自动检测编码;chrome中工具-->编码
'text/application;charset=utf8-8'
wsgi server服务器端:
需调用符合上述定义的可调用对象,传入environ、start_response,拿到返回的可迭代对象,返回给客户端;
wsgiref库
是一个wsgi参考实现库,仅测试用,生产不能用;
wsgiref.simple_server,实现一个简单的wsgi http服务器;
from wsgiref import simple_server
simple_server.make_server(host, port, app, server_class=WSGIServer, handler_class=WSGIRequestHandler): #启动一个wsgi server
simple_server.demo_app(environ,start_response): #一个函数,小巧完整的wsgi app的实现
例:
from wsgiref.simple_server import make_server, demo_app
ip = '127.0.0.1'
port = 9999
server = make_server(ip, port, demo_app)
server.serve_forever() #另server.handle_request()一次,Handle one request, possibly blocking.
server.shutdown()
server.server_close()
例:
from wsgiref.simple_server import make_server
def application(environ:dict, start_response):
print(type(environ))
html = '
test
'start_response("200 OK", [('Content-Type', 'text/html; charset=utf-8')])
return [html.encode()] #encode()同encode("utf-8")
ip = '127.0.0.1'
port = 9999
server = make_server(ip, port, application)
server.serve_forever()
server.shutdown()
server.server_close()
输出:
127.0.0.1 - - [10/Sep/2018 11:20:40] "GET / HTTP/1.1" 200 13
127.0.0.1 - - [10/Sep/2018 11:20:40] "GET /favicon.ico HTTP/1.1" 200 13
chrome:
工具-->编码;
工具-->开发者工具-->Network,左侧Name处点cn.bing.com,右侧查看Headers,view source或view parsed;
测试用命令:
curl -I http://ip:port/xxx?id=5 #-I,使用HEAD方法
curl -X POST http://ip:port/yyy -d '{'x':2} #-X指定方法,-d传输数据
QUERY_STRING查询字符串解析:
1、自己解析:
例:
def application(environ:dict, start_response):
qstr = environ.get('QUERY_STRING')
print(qstr) #拿到id=5&name=jowin
for pair in qstr.split('&'):
k,_,v = pair.partition('=')
print(k,v)
html = '
test
'start_response("200 OK", [('Content-Type', 'text/html; charset=utf-8')])
return [html.encode()]
输出:
id=5&name=jowin
id 5
name jowin
2、使用cgi模块:
def parse_qs(qs, keep_blank_values=0, strict_parsing=0):
"""Parse a query given as a string argument."""
warn("cgi.parse_qs is deprecated, use urllib.parse.parse_qs instead",
DeprecationWarning, 2)
return urllib.parse.parse_qs(qs, keep_blank_values, strict_parsing)
cgi.parse_qs(qs)已过期,建议使用urllib.parse.parse_qs(qs)
例:
def application(environ:dict, start_response):
qstr = environ.get('QUERY_STRING')
print(qstr)
import cgi
print(cgi.parse_qs(qstr)) #转为dict
html = '
test
'start_response("200 OK", [('Content-Type', 'text/html; charset=utf-8')])
return [html.encode()]
输出:
id=5&name=jowin
{'id': ['5'], 'name': ['jowin']}
例:
def application(environ:dict, start_response):
qstr = environ.get('QUERY_STRING')
print(qstr)
from urllib.parse import parse_qs,parse_qsl
print(parse_qs(qstr)) #dict;若query_string为?id=5&name=jowin,tom,解析结果为{'name': ['jowin,tom'], 'id': ['5']},注意['jowin,tom']不是多值;若query_string为?id=5&name=jowin&name=tom&age=&age=18,19,解析结果为{'name': ['jowin', 'tom'], 'id': ['5'], 'age': ['18,19']}
print(parse_qsl(qstr)) #二元组列表;若query_string为?id=5&name=jowin,tom,解析结果为[('id', '5'), ('name', 'jowin,tom')];若query_string为?id=5&name=jowin&name=tom&age=&age=18,19,[('id', '5'), ('name', 'jowin'), ('name', 'tom'), ('age', '18,19')]
html = '
test
'start_response("200 OK", [('Content-Type', 'text/html; charset=utf-8')])
return [html.encode()]
输出:
id=5&name=jowin
{'name': ['jowin'], 'id': ['5']}
[('id', '5'), ('name', 'jowin')]
文章题目:49web开发1_http_wsgiref
本文路径:http://pwwzsj.com/article/ipopcd.html