2012-03-17 9 views
5

Ho lavorato con l'installazione di Python come applicazione CGI su IIS su Windows 7. Questo è piuttosto semplice, ma mi piacerebbe utilizzare la roba WSGI, per una maggiore flessibilità.Come installare correttamente isapi_wsgi su IIS per Python2.7?

Ho scaricato l'archivio per isapi_wsgi, scompattato, e poi corse l'installazione come per the instructions, in questo modo:

\python27\python.exe setup.py install 

Questa riuscito:

enter image description here

Poi ho codificato a. modulo py che conteneva la colla wsgi e ha provato a installarlo. Questo non è riuscita in questo modo:

enter image description here

Si tratta di un errore di COM Moniker, e so che la roba gestione compatibile con IIS6 si basa su COM moniker, che mi ha ricordato che c'è un pre-req per isapi_wsgi del Roba di gestione compatibile con IIS6. Ho eseguito \windows\system32\OptionalFeatures.exe e l'ho installato, quindi ho rieseguito il modulo .py e l'ho installato correttamente.

C:\dev\wsgi>\Python27\python.exe app1_wsgi.py 
Configured Virtual Directory: /wsgi 
Installation complete. 

Ok, meraviglioso. Ora quando guardo nella directory corrente, vedo una nuova DLL chiamata _app1_wsgi.dll, e quando guardo in IIS Manager posso vedere un nuovo vdir di IIS, e una mappa di script all'interno di quel vdir per '*', che è mappato al _app1_wsgi.DLL. Tutto bene. Ma! fare una richiesta a http://localhost/wsgi mi dà un errore 500.

Attraverso alcuni tentativi ed errori vedo che il modulo .py che definisce i miei gestori deve trovarsi nella directory dei pacchetti del sito. Sono molto sorpreso da questo.

Posso evitare questo? Posso semplicemente inserire il modulo .py nella stessa directory del file .dll generato? O devo distribuire tutta la mia logica python ai pacchetti del sito per eseguirlo dal meccanismo WSGI?

+0

Eh? No. Questo non è un server, è una workstation di sviluppo. Sto facendo una domanda su una pratica di sviluppo di python. – Cheeso

risposta

1

La risposta è:

  • l'installazione di isapi_wsgi come descritto nella domanda, è corretto.

  • con la piastra di base di app.py come mostrato nel codice di esempio che accompagna isapi_wsgi, le classi python per l'app web devono essere nella directory dei siti-pacchetti.

  • è possibile consentire ai moduli di origine Python di risiedere nella stessa directory del file * .dll generato, ma richiede una gestione speciale nel file * wsgi.py.

  • un modo migliore per eseguire python su Windows per scopi di sviluppo è semplicemente scaricare Google App Engine e utilizzare il server http dedicato incorporato. Il framework fornito con l'SDK di GAE gestisce il ricaricamento e consente di posizionare i moduli .py in determinate directory.


Se non si desidera scaricare e installare l'SDK GAE, allora si potrebbe provare quanto segue. Usando questo codice, quando arriva una richiesta su isapi_wsgi, il gestore guarda nella directory home per un modulo py e lo carica.Se il modulo è già caricato, controlla il file "last modified time" e ricarica il modulo se l'ultima mod time è successiva all'ora dal carico precedente. Funziona per casi semplicistici ma suppongo che sarà fragile quando ci sono dipendenze del modulo nidificate.

import sys 
import os 
import win32file 
from win32con import * 

# dictionary of [mtime, module] tuple; uses file path as key 
loadedPages = {} 

def request_handler(env, start_response): 
    '''Demo app from wsgiref''' 
    cr = lambda s='': s + '\n' 
    if hasattr(sys, "isapidllhandle"): 
     h = None 
     # get the path of the ISAPI Extension DLL 
     hDll = getattr(sys, "isapidllhandle", None) 
     import win32api 
     dllName = win32api.GetModuleFileName(hDll) 
     p1 = repr(dllName).split('?\\\\') 
     p2 = p1[1].split('\\\\') 
     sep = '\\' 
     homedir = sep.join(p2[:-1]) 

     # the name of the Python module is in the PATH_INFO 
     moduleToImport = env['PATH_INFO'].split('/')[1] 

     pyFile = homedir + sep + moduleToImport + '.py' 

     fd = None 
     try: 
      fd = win32file.CreateFile(pyFile, GENERIC_READ, FILE_SHARE_DELETE, None, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0) 
     except Exception as exc1: 
      fd = None 

     if fd is not None: 
      # file exists, get mtime 
      fd.close() 
      mt = os.path.getmtime(pyFile) 
     else: 
      mt = None 


     if mt is not None: 
      h = None 
      if not pyFile in loadedPages: 
       # need a new import 
       if homedir not in sys.path: 
        sys.path.insert(0, homedir) 

       h = __import__(moduleToImport, globals(), locals(), []) 
       # remember 
       loadedPages[pyFile] = [mt, h] 
      else: 
       # retrieve handle to module 
       h = loadedPages[pyFile][1] 
       if mt != loadedPages[pyFile][0]: 
        # need to reload the page 
        reload(h) 
        loadedPages[pyFile][0] = mt 

      if h is not None: 
       if 'handler' in h.__dict__: 
        for x in h.handler(env, start_response): 
         yield x 
       else: 
        start_response("400 Bad Request", [('Content-Type', 'text/html')]) 
      else: 
       start_response("404 Not Found", [('Content-Type', 'text/html')]) 
       yield cr() 
       yield cr("<html><head><title>Module not found</title>" \ 
          "</head><body>") 
       yield cr("<h3>404 Not Found</h3>") 
       yield cr("<h3>No handle</h3></body></html>") 

     else: 
      start_response("404 Not Found", [('Content-Type', 'text/html')]) 
      yield cr() 
      yield cr("<html><head><title>Module not found</title>" \ 
       "</head><body>") 
      yield cr("<h3>404 Not Found</h3>") 
      yield cr("<h3>That module (" + moduleToImport + ") was not found.</h3></body></html>") 


    else: 
     start_response("500 Internal Server Error", [('Content-Type', 'text/html')]) 
     yield cr() 
     yield cr("<html><head><title>Server Error</title>" \ 
       "</head><body><h1>Server Error - No ISAPI Found</h1></body></html>") 


# def test(environ, start_response): 
#  '''Simple app as per PEP 333''' 
#  status = '200 OK' 
#  start_response(status, [('Content-type', 'text/plain')]) 
#  return ['Hello world from isapi!'] 


import isapi_wsgi 
# The entry point(s) for the ISAPI extension. 
def __ExtensionFactory__(): 
    return isapi_wsgi.ISAPISimpleHandler(request_handler) 


def PostInstall(params, options): 
    print "The Extension has been installed" 


# Handler for our custom 'status' argument. 
def status_handler(options, log, arg): 
    "Query the status of the ISAPI?" 
    print "Everything seems to be fine..." 


if __name__=='__main__': 
    # This logic gets invoked when the script is run from the command-line. 
    # In that case, it installs this module as an ISAPI. 

    # 
    # The API provided by isapi_wsgi for this is a bit confusing. There 
    # is an ISAPIParameters object. Within that object there is a 
    # VirtualDirs property, which itself is a list of 
    # VirtualDirParameters objects, one per vdir. Each vdir has a set 
    # of scriptmaps, usually this set of script maps will be a wildcard 
    # (*) so that all URLs in the vdir will be served through the ISAPI. 
    # 
    # To configure a single vdir to serve Python scripts through an 
    # ISAPI, create a scriptmap, and stuff it into the 
    # VirtualDirParameters object. Specify the vdir path and other 
    # things in the VirtualDirParameters object. Stuff that vdp object 
    # into a sequence and set it into the ISAPIParameters thing, then 
    # call the vaguely named "HandleCommandLine" function, passing that 
    # ISAPIParameters thing. 
    # 
    # Clear as mud? 
    # 
    # Seriously, this thing could be so much simpler, if it had 
    # reasonable defaults and a reasonable model, but I guess it will 
    # work as is. 

    from isapi.install import * 

    # Setup the virtual directories - 
    # To serve from root, set Name="/" 
    sm = [ ScriptMapParams(Extension="*", Flags=0) ] 
    vdp = VirtualDirParameters(Name="wsgi", # name of vdir/IIS app 
           Description = "ISAPI-WSGI Demo", 
           ScriptMaps = sm, 
           ScriptMapUpdate = "replace" 
          ) 

    params = ISAPIParameters(PostInstall = PostInstall) 
    params.VirtualDirs = [vdp] 
    cah = {"status": status_handler} 

    # from isapi.install, part of pywin32 
    HandleCommandLine(params, custom_arg_handlers = cah) 

Utilizzando questo modello, chiedendo http://foo/wsgi/bar cercherà di carico bar.py dalla home directory con il file dll WSGI. Se non riesci a trovare bar.py, ottieni un 404. Se bar.py è stato aggiornato dall'ultima esecuzione, viene ricaricato. Se la barra non può essere caricata, si ottiene un 500.

bar.py deve esportare un metodo chiamato handler, pubblicamente. Quel metodo deve essere un generatore. in questo modo:

import time 

def handler(env, start_response): 
    start_response("200 OK", [('Content-Type', 'text/html')]) 
    cr = lambda s='': s + '\n' 
    yield cr("<html><head><title>Hello world!</title></head><body>") 
    yield cr("<h1>Bargle Bargle Bargle</h1>") 
    yield cr("<p>From the handler...</p>") 
    yield cr("<p>(bargle)</p>") 
    yield cr("<p>The time is now: " + time.asctime() + " </p>") 
    yield cr("</body></html>") 

__all__ = ['handler'] 

Ma come ho detto, penso GAE è probabilmente un modo migliore per sviluppare webapps Python che utilizzano Windows.

-2

mettere questo in cima alla vostra bisaccia:

sito importazione site.addsitedir ('path/to/tuoi/site-packages')

lo stesso problema si ha, è stato risolto con questo due linee

Problemi correlati