[英]How to properly install isapi_wsgi on IIS for Python2.7?
我已經在Windows 7上的IIS上安裝了Python作為CGI應用程序。這非常簡單,但我想使用WSGI的東西,以獲得更好的靈活性。
我下載了isapi_wsgi的存檔, 解壓縮它,然后根據說明運行安裝,如下所示:
\python27\python.exe setup.py install
這成功了:
然后我編寫了一個帶有wsgi膠水的.py模塊,並嘗試安裝它。 這樣失敗了:
這是一個COM Moniker錯誤,我知道IIS6兼容的管理內容基於COM Monikers,這提醒我有一個isapi_wsgi與IIS6兼容管理內容的預先請求。 我運行\\windows\\system32\\OptionalFeatures.exe
並安裝它,然后重新運行.py模塊並正確安裝。
C:\dev\wsgi>\Python27\python.exe app1_wsgi.py
Configured Virtual Directory: /wsgi
Installation complete.
好的,很好。 現在,當我查看當前目錄時,我看到一個名為_app1_wsgi.dll的新DLL,當我查看IIS管理器時,我可以看到一個新的IIS vdir,以及該vdir中用於'*'的腳本映射,它映射到_app1_wsgi.DLL。 都好。 但! 向http://localhost/wsgi
發出請求給出了500錯誤。
通過一些反復試驗,我發現定義我的處理程序的.py模塊必須位於site-packages目錄中。 我對此感到非常驚訝。
我可以避免這個嗎? 我可以簡單地將.py模塊放在與生成的.dll文件相同的目錄中嗎? 或者我是否需要將所有python邏輯部署到site-packages以便從WSGI機制運行它?
答案是:
如問題中所述安裝isapi_wsgi是正確的。
使用app.py的基本樣板,如isapi_wsgi附帶的示例代碼所示,Web應用程序的python類需要位於site-packages目錄中。
可以允許python源模塊與生成的* .dll文件駐留在同一目錄中,但它需要在* wsgi.py文件中進行一些特殊處理。
在Windows上運行python以進行開發的更好方法是簡單地下載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將嘗試使用WSGI .dll文件從主目錄加載bar.py. 如果找不到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可能是使用Windows開發Python webapps的更好方法。
把它放在你的腳本之上:
導入站點site.addsitedir('path / to / your / site-packages')
你有同樣的問題,用這兩行解決了
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.