http.server用pyinstaller打包后无法处理http请求

最近编写了一个简单的小程序,qt做的界面,点击按钮后用多线程启动一个httpserver,用python解释器运行时没有任何问题,但是使用pyinstaller打包成exe后,发现点击按钮,接受到的http请求并未做处理,代码如下

httpserver的post处理如下(处理过程可忽略,特定解析用的):

class HTTPServerRequestHandler(BaseHTTPRequestHandler):

    def do_POST(self):
        '''
        接收POST请求
        :return:
        '''
        
        print("=====================================================")
        print("用户提交post请求,开始处理post请求...")
        querypath = urlparse(self.path)
        print("当前post的url是" + querypath.path)  # 
        post_type = querypath.path.split("/")[1]  # 
        try:    # 先执行try代码,发现的错误执行except代码,程序向下执行
            post_params = querypath.path.split("/")[2]  # 
        except:
            post_params = None

        self.do_post_handle(post_type, post_params)  # 处理post请求
        print("收到对端请求...")

        print("post请求处理完成...")
            
        print("=================================================")

    def do_post_handle(self, post_type, post_params):  # 

            print("当前处理的是[%s]" % post_type)
            req_datas = self.rfile.read(int(self.headers['content-length'])).decode('utf-8')
            print("post请求数据为:%s " % req_datas)

            req_name = req_datas.split(',')[0]
            req_name = req_name.split(':')[1]
            if req_name == self.Name:
                if isinstance(self.SWFile, dict):
                    data = []
                    for md, urlItem in self.SWFile.items():
                        urlItem = 'http://192.168.137.80:80/%s' % urlItem
                        data.append(
                            {
                                "ModuleID": md,
                                "URL": urlItem
                            }
                        )
                print(data)
                self.send_response(200)   # 响应码200
                self.send_header('Content-type', 'application/json')
                self.end_headers()
                self.wfile.write(json.dumps(data).encode('utf-8'))  


class httpserverThread(Thread): #(使用Thread定义多线程启动入口)
    def __init__(self):
        super().__init__()
        self.SERVER_IP = "192.168.137.80"  # 本机地址
        self.SERVER_PORT = 80  # 本机端口
        server_address = (self.SERVER_IP, self.SERVER_PORT)
        self.httpd = HTTPServer(server_address, HTTPServerRequestHandler)

    def run(self):
        try:
            print('server started....')
            self.httpd.serve_forever()
        except:
            print('server start error')

    def stop(self):
        self.httpd.shutdown()

然后在主程序中启动httpserver

ser = httpserver.httpserverThread()
ser.start()

使用python解释器运行完全没有问题,但是程序是要给别的人使用,所以使用pyinstaller打包成exe

参数是-D -w

pyinstaller -D -w main.py

实际使用中别的功能都没问题,但是httpserver使用不响应http的请求,一开始我以为是多线程未启动,但是增加了print函数后,又打包成带命令行界面的exe,即

pyinstaller -D main.py

重新调试,发现此时httpserver正常响应了,由此判定应该是由于pyinstaller的 -w参数  即 nonconsole引起的httpserver响应异常,于是网上搜索相关内容,发现pyinstaller 的-w(即nonconsole)对httpserver中的send_response有影响,如果导致程序无法往下运行,解决办法有两个

1、要么就使用带命令行的exe,但是有点丑陋,不采用

2、把send_response函数更换成send_response_only即可,如下

    def do_post_handle(self, post_type, post_params):  # 

            print("当前处理的是[%s]" % post_type)
            req_datas = self.rfile.read(int(self.headers['content-length'])).decode('utf-8')
            print("post请求数据为:%s " % req_datas)

            req_name = req_datas.split(',')[0]
            req_name = req_name.split(':')[1]
            if req_name == self.Name:
                if isinstance(self.SWFile, dict):
                    data = []
                    for md, urlItem in self.SWFile.items():
                        urlItem = 'http://192.168.137.80:80/%s' % urlItem
                        data.append(
                            {
                                "ModuleID": md,
                                "URL": urlItem
                            }
                        )
                print(data)
                self.send_response_only(200)   # 响应码200
                self.send_header('Content-type', 'application/json')
                self.end_headers()
                self.wfile.write(json.dumps(data).encode('utf-8')) 

查看两个函数的区别,send_response需要先将内容写到缓存中,而send_response_only直接将内容输出到output stream中,看一下两个函数的源码

    def send_response(self, code, message=None):
        """Add the response header to the headers buffer and log the
        response code.

        Also send two standard headers with the server software
        version and the current date.

        """
        self.log_request(code)
        self.send_response_only(code, message)
        self.send_header('Server', self.version_string())
        self.send_header('Date', self.date_time_string())

    def send_response_only(self, code, message=None):
        """Send the response header only."""
        if self.request_version != 'HTTP/0.9':
            if message is None:
                if code in self.responses:
                    message = self.responses[code][0]
                else:
                    message = ''
            if not hasattr(self, '_headers_buffer'):
                self._headers_buffer = []
            self._headers_buffer.append(("%s %d %s\r\n" %
                    (self.protocol_version, code, message)).encode(
                        'latin-1', 'strict'))

最大的问题应该就在于,除了缓存之外,还将数据记录了log

self.log_request(code)
看一下源码
    def log_request(self, code='-', size='-'):
        """Log an accepted request.

        This is called by send_response().

        """
        if isinstance(code, HTTPStatus):
            code = code.value
        self.log_message('"%s" %s %s',
                         self.requestline, str(code), str(size))    

    def log_message(self, format, *args):

        message = format % args
        sys.stderr.write("%s - - [%s] %s\n" %
                         (self.address_string(),
                          self.log_date_time_string(),
                          message.translate(self._control_char_table)))

这样一看问题应该就很明确了,对于pyinstaller nonconsole的打包方式,不带有控制台,所以应该是没有办法处处理stdin、stdout、stderr之类的内容,导致函数运行错误。所以各位老铁也可以尝试把log的内容删除,或者直接用send_response_only就行

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值