Python basehttpserver не обслуживает запросы должным образом - PullRequest
2 голосов
/ 06 декабря 2011

Я пытаюсь записать простой локальный прокси для 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, однако, я заметил, что иногда это не работает или зависает в течение длительного времени ... что случилось, интересно?Я что-то не так сделал?

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

Ответы [ 2 ]

8 голосов
/ 03 июля 2013

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

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

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

Threads! .. и 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, чтобы порождать другой процесс вместо другого потока. всего наилучшего, Creo

0 голосов
/ 07 декабря 2011

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

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

...