Как правильно установить isapi_wsgi на IIS для Python2.7? - PullRequest
5 голосов
/ 18 марта 2012

Я работал над установкой Python в качестве CGI-приложения на IIS в Windows 7. Это довольно просто, но я бы хотел использовать WSGI для большей гибкости.

Я скачал архив для isapi_wsgi , распаковал его, а затем запустил установку согласно инструкциям , например:

\python27\python.exe setup.py install

Это удалось:

enter image description here

Затем я закодировал модуль .py, в котором был клей wsgi, и попытался установить его.Это не удалось так:

enter image description here

Это ошибка COM Moniker, и я знаю, что IIS6-совместимые средства управления основаны на COM Monikers, что напомнило мне, что-req для isapi_wsgi из IIS6-совместимого средства управления.Я запустил \windows\system32\OptionalFeatures.exe и установил его, затем повторно запустил модуль .py, и он установился правильно.

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

Хорошо, замечательно.Теперь, когда я смотрю в текущем каталоге, я вижу новую DLL с именем _app1_wsgi.dll, и когда я смотрю в IIS Manager, я вижу новый VISD IIS и карту сценариев в этом VDIR для «*», которая сопоставлена ​​с_app1_wsgi.DLL.Все хорошо.Но!выполнение запроса к <a href="http://localhost/wsgi" rel="noreferrer">http://localhost/wsgi</a> дает мне ошибку 500.

В результате некоторых проб и ошибок я вижу, что модуль .py, который определяет мои обработчики , должен находиться в пакетах сайта каталог.Я очень удивлен этим.

Можно ли этого избежать?Могу ли я просто поместить модуль .py в тот же каталог, что и сгенерированный файл .dll?Или мне нужно развернуть всю мою логику python в пакетах сайтов, чтобы запустить ее из механизма WSGI?

Ответы [ 2 ]

1 голос
/ 20 марта 2012

Ответ:

  • установка isapi_wsgi, как описано в вопросе, является правильной.

  • с базовым шаблоном app.py, как показано в примере кода, сопровождающего isapi_wsgi, классы python для веб-приложения должны находиться в каталоге site-packages.

  • можно разрешить исходным модулям python находиться в том же каталоге, что и сгенерированный файл * .dll, но это требует некоторой специальной обработки в файле * wsgi.py.

  • лучший способ запустить python в Windows для целей разработки - просто загрузить Google App Engine и использовать встроенный выделенный http-сервер. Платформа, которая поставляется с GAE SDK, выполняет перезагрузку и позволяет размещать модули .py в определенных каталогах.


Если вы не хотите загружать и устанавливать GAE SDK, попробуйте следующее. Используя этот код, когда на isapi_wsgi приходит запрос, обработчик ищет в домашнем каталоге модуль py и загружает его. Если модуль уже загружен, он проверяет файл «время последнего изменения» и перезагружает модуль, если время последнего мода позже, чем время от предыдущей загрузки. Это работает для упрощенных случаев, но я предполагаю, что это будет хрупко, когда есть вложенные зависимости модуля.

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)

При использовании этой модели запрос http://foo/wsgi/bar попытается загрузить bar.py из домашнего каталога с файлом WSGI .dll. Если bar.py не может быть найден, вы получите 404. Если bar.py был обновлен с момента последнего запуска, он перезагружается. Если бар не может быть загружен, вы получите 500.

bar.py должен экспортировать метод с именем handler, публично. Этот метод должен быть генератором. вот так:

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']

Но, как я уже сказал, я думаю, что GAE, вероятно, является лучшим способом разработки веб-приложений Python с использованием Windows.

0 голосов
/ 21 февраля 2015

поместите это поверх вашего скрипта:

сайт импорта site.addsitedir ( 'путь / к / вашим / сайт-пакеты')

та же проблема, что и у вас, была решена с помощью этих двух строк

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...