热门IT资讯网

49web开发1_http_wsgiref

发表于:2024-11-26 作者:热门IT资讯网编辑
编辑最后更新 2024年11月26日,目录cs和bs:... 1http协议:... 2http消息:... 3Request:... 3常见传递信息的方式:... 3Response:... 4wsgi:... 5wsgi app应用程

目录

csbs... 1

http协议:... 2

http消息:... 3

Request... 3

常见传递信息的方式:... 3

Response... 4

wsgi... 5

wsgi app应用程序端:... 6

wsgi server服务器端:... 7

测试用命令:... 9

QUERY_STRING查询字符串解析:... 9

web开发:

csbs

cs之间需使用socket,约定协议、版本(往往使用tcpudp),指定地址和端口,就可以通信;

cs传输数据,数据可以有一定的格式,双方必须先约定好;

bs

b,一种特殊client,支持http(s)协议,能通过url向服务器发起请求,等待服务器端返回html等数据,并在browser内可视化展示的程序;

s,支持http(s),能接受众多客户端发起的http协议请求,经过处理,将html等数据返回给b

本质上,bs是一种特殊的cs

即客户端必须是一种支持http协议且能解析并渲染html的软件;

服务端必须是能接收多客户端的http访问的服务器软件;

客户端开发或前端开发;

服务端开发,py可学wsgidjangoflasktornado等;

pyweb框架:

早期cgi

wsgiweb server gateway interface,可看作是一种底层协议,它规定了服务器程序和应用程序各自实现什么接口,py的实现为wsgiref库;

flask,基于wsgi,微框架;

django,基于wsgi,开源的web框架,巨无霸;

http协议:

无状态的面向连接的协议;

无状态,同一个客户端的两次请求,从服务端角度来说,它并不知道这两个请求来自同一个客户端;

解决:通过cookiesessiontoken)来判断;

面向连接:

有连接,基于tcp是面向连接,需3次握手4次断开;

短连接http1.0是一个请求一个连接,而tcp创建销毁成本高,对server有很大影响;http1.1,支持keep-alive,默认开启,一个连接打开后会保持一段时间(可设置),b再访问该s就使用这个tcp连接,减轻了服务器压力,提高了效率;

cookie

为解决http的无状态,用到cookiesessionIDtoken);

一般,cookie信息是服务端生成,返回给客户端的;

客户端可自己设置cookie信息;

键值对信息,有时效;

browser发起每一个请求时,都会把cookie信息发给服务端;

是一种客户端、服务端传递数据的技术;

服务端可通过判断这些信息,来确定这次请求是否和之前的请求有关联,服务端为了认识同一个client,用sessionIDtokensessionIDtoken可理解为是一种标识,这些标识要么通过cookie带,要么通过url带,要么通过request body带;

注:

sessionID,保存在服务端内存中,随着会话关闭而消亡;

token,替代sessionIDserver发给client的令牌,server通过此标识来认client

url组成:

uniform resource locator统一资源定位符,每一个链接指向一个资源供客户端访问;

schema://host[:port#]/path/.../[;url-params][?query-string][#anchor]

schema,模式、协议,httpftpfilemailtomysql等;

host:port80默认可不写,有域名解析,实际上应该是IP

/path/to/resourcepath指向资源的路径;

?key1=value1&key2=value2query string查询字符串,问号分割,后面key=value形式且用&分割

http消息:

分为RequestResponse,请求和响应都由请求消息行(请求行)、header消息报头、body消息正文组成;

Request

request method请求方法:

GET,请求获取url对应的资源;

POST,提交数据至服务器端;

HEAD,和GET类似,不过不返回消息正文;

例:

GET / HTTP/1.1 #请求行,分别为:请求方法 请求路径 协议版本CRLFCRLF为回车换行

Host:

User-Agent:

Accept:

Accept-Language:

Accept-Encoding:

Cookie:

Connection:

Upgrade-Insecure-Requests: #header消息报头

body: #两个CRLF后是body

常见传递信息的方式:

1GET方法使用query string

例:

http://www.magedu.com/python/index.html?id=5&name=python

2POST方法提交数据:

例:

http://127.0.0.1:9999/xxx/yyy?id=5&name=python

使用表单提交数据,文本框nameageweigthheight

请求消息如下:

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

3url中本身就包含着信息:

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,正常返回了网页内容;

201Created

3XX,重定向;

301,页面永久性移走,永久重定向,返回新的urlb会根据返回的url发起新的request请求;

302,临时重定向;

304,资源未修改,b使用本地缓存;

4XX,客户端请求错误;

404Not 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、以上三种实现(三种都有用,框架简单用函数,框架复杂用类多些,更复杂都用),必须返回一个可迭代对象;

environstart_response参数:

这两个参数可以是任何合法名,一般默认用这两个名字;

environ,是包含http请求信息的dict对象:

REQUEST_METHOD #请求方法,GETPOST

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服务器端:

需调用符合上述定义的可调用对象,传入environstart_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,右侧查看Headersview sourceview 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')]


0