读webpy源码-请求响应1

本文深入探讨webpy框架的请求响应流程,重点关注如何从socket接收HTTP报文并转化为request对象,以及如何解析URL信息匹配到相应的处理类。
摘要由CSDN通过智能技术生成

上一篇简述了webpy响应流程过程,这里着重讲下可能大家关心的细节点。
运行时启动一个socket(默认8080端口),当在浏览器请求url发起时,就是向这个socket发送了http协议的报文。socket收到后会解析包装成request对象,然后调用application的方法返回。
后面主要看看解析做了什么?响应又是怎么做的? 本人的主要思路是:

  1. 在哪里解析出url中的信息(比如path,param)
  2. 在哪里根据解析出来的信息找到对应的处理类(根据web.ctx.path映射到handlerClass)

因为主要流程在上一篇已经阐述过,所以这里直接重点看下解析部分。

        httpserver.runsimple(func, validip(listget(sys.argv, 1, '')))


--> #全局变量,后面的server.start()里面就用self.server方式把server放入到WorkThread中。 server = None def runsimple(func, server_address=("0.0.0.0", 8080)): global server func = StaticMiddleware(func) func = LogMiddleware(func) #这里会把wsgi_app(即func)填充到server,这样后面respond响应时就可以调用self.server.wsgi_app了 server = WSGIServer(server_address, func) if server.ssl_adapter: print "https://%s:%d/" % server_address else: print "http://%s:%d/" % server_address try: server.start() except (KeyboardInterrupt, SystemExit): server.stop() server = None
--------------------> #server.start() def start(self): self._interrupt = None if self.software is None: self.software = "%s Server" % self.version if (self.ssl_adapter is None and getattr(self, 'ssl_certificate', None) and getattr(self, 'ssl_private_key', None)): warnings.warn( "SSL attributes are deprecated in CherryPy 3.2, and will " "be removed in CherryPy 3.3. Use an ssl_adapter attribute " "instead.", DeprecationWarning ) try: from cherrypy.wsgiserver.ssl_pyopenssl import pyOpenSSLAdapter except ImportError: pass else: self.ssl_adapter = pyOpenSSLAdapter( self.ssl_certificate, self.ssl_private_key, getattr(self, 'ssl_certificate_chain', None)) if isinstance(self.bind_addr, basestring): try: os.unlink(self.bind_addr) except: pass try: os.chmod(self.bind_addr, 0777) except: pass info = [(socket.AF_UNIX, socket.SOCK_STREAM, 0, "", self.bind_addr)] else: host, port = self.bind_addr try: info = socket.getaddrinfo(host, port, socket.AF_UNSPEC, socket.SOCK_STREAM, 0, socket.AI_PASSIVE) except socket.gaierror: if ':' in self.bind_addr[0]: info = [(socket.AF_INET6, socket.SOCK_STREAM, 0, "", self.bind_addr + (0, 0))] else: info = [(socket.AF_INET, socket.SOCK_STREAM, 0, "", self.bind_addr)] self.socket = None msg = "No socket could be created" for res in info: af, socktype, proto, canonname, sa = res try: self.bind(af, socktype, proto) except socket.error: if self.socket: self.socket.close() self.socket = None continue break if not self.socket: raise socket.error(msg) self.socket.settimeout(1) self.socket.listen(self.request_queue_size) #由这里进入看request的解析 self.requests.start() self.ready = True self._start_time = time.time() while self.ready: self.tick() if self.interrupt: while self.interrupt is True: time.sleep(0.1) if self.interrupt: raise self.interrupt
------------------> def start(self): for i in range(self.min): #可以看到WorkerThread是一个线程,主要用来处理request self._threads.append(WorkerThread(self.server)) for worker in self._threads: worker.setName("CP Server " + worker.getName()) worker.start() for worker in self._threads: while not worker.ready: time.sleep(.1)
--------------------> def run(self): self.server.stats['Worker Threads'][self.getName()] = self.stats try: self.ready = True while True: conn = self.server.requests.get() if conn is _SHUTDOWNREQUEST: return self.conn = conn if self.server.stats['Enabled']: self.start_time = time.time() try: #这里是解析入口 conn.communicate() finally: conn.close() if self.server.stats['Enabled']: self.requests_seen += self.conn.requests_seen self.bytes_read += self.conn.rfile.bytes_read self.bytes_written += self.conn.wfile.bytes_written self.work_time += time.time() - self.start_time self.start_time = None self.conn = None except (KeyboardInterrupt, SystemExit), exc: self.server.interrupt = exc
------------------> def communicate(self): request_seen = False try: while True: req = None req = self.RequestHandlerClass(self.server, self) #解析入口 req.parse_request() if self.server.stats['Enabled']: self.requests_seen += 1 if not req.ready: return request_seen = True #响应入口 req.respond() if req.close_connection: return
--------------------> def parse_request(self): self.rfile = SizeCheckWrapper(self.conn.rfile, self.server.max_request_header_size) try: #解析入口 self.read_request_line() except MaxSizeExceeded: self.simple_response("414 Request-URI Too Long", "The Request-URI sent with the request exceeds the maximum " "allowed bytes.") return try: success = self.read_request_headers() except MaxSizeExceeded: self.simple_response("413 Request Entity Too Large", "The headers sent with the request exceed the maximum " "allowed bytes.") return else: if not success: return self.ready = True
--------------------> def read_request_line(self): request_line = self.rfile.readline() self.started_request = True if not request_line: self.ready = False return if request_line == CRLF: request_line = self.rfile.readline() if not request_line: self.ready = False return if not request_line.endswith(CRLF): self.simple_response("400 Bad Request", "HTTP requires CRLF terminators") return try: method, uri, req_protocol = request_line.strip().split(" ", 2) rp = int(req_protocol[5]), int(req_protocol[7]) except (ValueError, IndexError): self.simple_response("400 Bad Request", "Malformed Request-Line") return self.uri = uri self.method = method scheme, authority, path = self.parse_request_uri(uri) if '#' in path: self.simple_response("400 Bad Request", "Illegal #fragment in Request-URI.") return if scheme: self.scheme = scheme qs = '' if '?' in path: path, qs = path.split('?', 1) try: atoms = [unquote(x) for x in quoted_slash.split(path)] except ValueError, ex: self.simple_response("400 Bad Request", ex.args[0]) return path = "%2F".join(atoms) #重点在这里有个说明,因为后面去做respond是根据path映射到对应的处理类上 #后面在回调wsgi_app时,会用self.path填充web.ctx.path #比如你的项目里有如此路径映射配置'/getJsonData', 'getJsonDataHandler';那么会根据web.ctx.path的请求路径/getJsonData找到对应的getJsonDataHandler处理类 self.path = path self.qs = qs sp = int(self.server.protocol[5]), int(self.server.protocol[7]) if sp[0] != rp[0]: self.simple_response("505 HTTP Version Not Supported") return self.request_protocol = req_protocol self.response_protocol = "HTTP/%s.%s" % min(rp, sp)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值