Python basehttpserver не обслуживает запросы должным образом

Я пытаюсь написать простой локальный прокси для javascript: поскольку мне нужно загрузить некоторые вещи из javascript на веб-страницу, я написал этот простой демон на python:

import string,cgi,time
from os import curdir, sep
import urllib
import urllib2

from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer


class MyHandler(BaseHTTPRequestHandler):



    def fetchurl(self, url, post, useragent, cookies):
        headers={"User-Agent":useragent, "Cookie":cookies}

        url=urllib.quote_plus(url, ":/?.&-=")
        if post:
            req = urllib2.Request(url,post,headers)
        else:
            req=urllib2.Request(url, None, headers)
        try:
            response=urllib2.urlopen(req)
        except urllib2.URLError, e:
            print "URLERROR: "+str(e)
            return False
        except urllib2.HTTPError, e:
            print "HTTPERROR: "+str(e)
            return False
        else:
            return response.read()


    def do_GET(self):
        if self.path != "/":
            [callback, url, post, useragent, cookies]=self.path[1:].split("%7C")

            print "callback = "+callback
            print "url = "+url
            print "post = "+post
            print "useragent = "+useragent
            print "cookies = "+cookies

            if useragent=="":
                useragent="pyjproxy v. 1.0"

            load=self.fetchurl(url, post, useragent, cookies)

            pack=load.replace("\\", "\\\\").replace("\"", "\\\"").replace("\n",         "\\n").replace("\r", "\\r").replace("\t", "\\t").replace("    </script>", "</scr\"+\"ipt>")
            response=callback+"(\""+pack+"\");"

            if load:
                self.send_response(200)
                self.send_header('Content-type',    'text/javascript')
                self.end_headers()
                self.wfile.write(response)
                self.wfile.close()
                return
            else:
                self.send_error(404,'File Not Found: %s' % self.path)
                return
        else:
            embedscript="function pyjload(datadict){  if(!datadict[\"url\"] ||             !datadict[\"callback\"]){return false;}  if(!datadict[\"post\"])             datadict[\"post\"]=\"\";  if(!datadict[\"useragent\"])     datadict[\"useragent\"]=\"\";  if(!datadict[\"cookies\"])     datadict[\"cookies\"]=\"\";  var oHead =                     document.getElementsByTagName('head').item(0);  var oScript=             document.createElement(\"script\");  oScript.type =         \"text/javascript\";  oScript.src=\"http://localhost:1180/\"+datadict[\"callback\"]+\"%7C\"+datadict[\"url\"]+\"%7C\"+datadict[\"post\"]+\"%7C\"+datadict[\"useragent\"]+\"%7C\"+datadict[\"cookies\"];  oHead.appendChild( oScript);}"
            self.send_response(200)
            self.send_header("Content-type", "text/html")
            self.end_headers()
            self.wfile.write(embedscript)
            self.wfile.close()
            return

def main():
    try:
        server = HTTPServer(('127.0.0.1', 1180), MyHandler)
        print 'started httpserver...'
        server.serve_forever()
    except KeyboardInterrupt:
        print '^C received, shutting down server'
        server.socket.close()

if __name__ == '__main__':
    main()

И я использую на веб-странице, подобной этой:

<!DOCTYPE HTML>
<html><head>

<script>
function miocallback(htmlsource)
{
  alert(htmlsource);
}


</script>

<script type="text/javascript" src="http://localhost:1180"></script>


</head><body>


<a onclick="pyjload({'url':'http://www.google.it','callback':'miocallback'});"> Take     the Red Pill</a>

</body></html>

Теперь в Firefox и Chrome, похоже, работает всегда. Однако в Opera и Internet Explorer я заметил, что иногда он не работает или зависает на долгое время... интересно, в чем дело? Я что-то не так сделал?

Спасибо за любую помощь! Маттео


person Matteo Monti    schedule 06.12.2011    source источник


Ответы (2)


Вы должны понимать, что (современные) браузеры пытаются оптимизировать скорость просмотра, используя разные методы, поэтому вы получаете разные результаты в разных браузерах.

В вашем случае метод, который вызвал у вас проблемы, — это параллельная настройка сеанса HTTP/1.1: чтобы лучше использовать пропускную способность, ваш браузер может запускать несколько сеансов HTTP/1.1 одновременно. Это позволяет одновременно получать несколько ресурсов (например, изображений).

Однако BaseHTTPServer не является многопоточным: как только ваш браузер попытается открыть другое соединение, он не сможет этого сделать, поскольку BaseHTTPServer уже заблокирован первым открытым сеансом. Запрос никогда не достигнет сервера и истечет время ожидания. Это также означает, что только один пользователь может получить доступ к вашему сервису в данный момент времени. Неудобно? Да, но помощь здесь:

Потоки! .. и python делает это довольно просто:

Получите новый класс от HTTPServer, используя MixIn от socketserver.

.

Пример:

from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler
from SocketServer import ThreadingMixIn
import threading

class Handler(BaseHTTPRequestHandler):

    def do_HEAD(self):
        pass

    def do_GET(self):
        pass


class ThreadedHTTPServer(ThreadingMixIn, HTTPServer):
    """ This class allows to handle requests in separated threads.
        No further content needed, don't touch this. """

if __name__ == '__main__':
server = ThreadedHTTPServer(('localhost', 80), Handler)
print 'Starting server on port 80...'
server.serve_forever()

С этого момента BaseHTTPServer является потоковым и готов обслуживать несколько соединений (и, следовательно, запросов) одновременно, что решит вашу проблему.

Вместо ThreadingMixIn вы также можете использовать ForkingMixIn, чтобы создать другой процесс вместо другого потока.

всего наилучшего,

крео

person Daniel creo Haslinger    schedule 03.07.2013

Обратите внимание, что Python basehttpserver — это очень простой HTTP-сервер, далекий от совершенства, но это не первая ваша проблема.

Что произойдет, если вы поместите два сценария в конец документа непосредственно перед тегом </body>? Это помогает?

person karlcow    schedule 07.12.2011