You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

将老旧Python Web应用改造为WSGI适配并部署于Apache环境

老旧Python CGI Web应用适配WSGI改造方案

问题背景

我有一个由Python编写的老旧Web应用,由多个.py文件组成,核心文件display.py示例代码如下:

import cgi
import re
import string
import operator
from urllib.parse import urlparse
from errors import herigean
from routines import *

error = False

query = cgiFieldStorageToDict(cgi.FieldStorage())
opening_index = 0 # flag to indicate whether we're opening the index page
if ('what' not in query):
        query['what'] = 'index'
if 'fs' not in query:
        query['fs'] = str(default_font_size)

# open page to display
try:
        fil = open('html/'+query['what']+'.fmt')
        textlines = fil.read()
        queryreg = re.compile('QUERY:fs:QUERY')
        textlines = queryreg.sub(query['fs'],textlines)
        fil.close()
except IOError:
        error = True

if query['what'] == 'about':
        try:
                fil = open('legal/lgpl-3.0.txt')
                lgpl = fil.read()
                fil.close()
                fil = open('legal/gpl.txt')
                gpl = fil.read()
                fil.close()
                fil = open('html/availability.fmt')
                availability = fil.read()
                fil.close()
        except IOError:
                error = True
if query['what'] == 'corpus':
        try:
                fil = open('html/availability.fmt')
[...]
if error:
        herigean()
else:
        print(frontmatter)

当前已在Python 3.11虚拟环境中安装mod_wsgi-express 5,能成功运行测试WSGI程序:

def application(environ, start_response):
    start_response('200 OK', [('Content-Type', 'text/html')])
    return [b'Hello, world!']

遇到的具体问题:

  • 不清楚如何改造原有应用适配WSGI,是否需要给每个.py文件都套上def application(environ, start_response):?
  • 尝试将代码包裹在application函数中时,用return print(frontmatter)导致日志输出完整HTML,但抛出TypeError: 'NoneType' object is not iterable错误,浏览器显示500内部服务器错误。
  • 应用通过www目录下的index.html跳转启动:<meta http-equiv="Refresh" content="0;url=display.py?what=index" />

改造解决方案

1. 无需给每个.py文件都套application函数

原有CGI应用的入口是display.py,只需要改造这个核心入口文件即可,其他依赖的.py文件(比如errors.py、routines.py)保持原样,只要确保WSGI环境能正确导入它们。

2. 替换CGI请求参数解析逻辑

原有代码用cgi.FieldStorage()获取请求参数,在WSGI环境下需要改用environ变量解析:

from urllib.parse import parse_qs

def get_query_params(environ):
    query_string = environ.get('QUERY_STRING', '')
    params = parse_qs(query_string)
    # 将多值参数转为单值,适配原有逻辑
    return {k: v[0] for k, v in params.items()}

替换原有的query = cgiFieldStorageToDict(cgi.FieldStorage())为query = get_query_params(environ)。

3. 修复return语句的错误

print(frontmatter)会输出内容到标准输出,但WSGI要求返回字节数组组成的可迭代对象,且print()函数返回None,这就是报错的核心原因。需要:

  • 去掉print()调用,直接返回编码后的字节内容
  • 将HTML字符串转为字节数组(比如frontmatter.encode('utf-8'))

4. 改造错误处理函数herigean()

原有的herigean()应该是直接输出错误页面到标准输出,需要修改它返回错误页面的字符串内容,然后在WSGI逻辑中正确调用:

# 假设修改后的herigean()返回错误页面字符串
if error:
    error_content = herigean()
    start_response('500 Internal Server Error', [('Content-Type', 'text/html')])
    return [error_content.encode('utf-8')]

5. 完整改造后的display.py示例

import re
import string
import operator
from urllib.parse import urlparse, parse_qs
from errors import herigean
from routines import *

def get_query_params(environ):
    query_string = environ.get('QUERY_STRING', '')
    params = parse_qs(query_string)
    return {k: v[0] for k, v in params.items()}

def application(environ, start_response):
    error = False
    query = get_query_params(environ)
    
    opening_index = 0
    if 'what' not in query:
        query['what'] = 'index'
    if 'fs' not in query:
        query['fs'] = str(default_font_size)

    # 读取页面内容逻辑保持不变,改用with语句更安全
    try:
        with open(f'html/{query["what"]}.fmt', 'r') as fil:
            textlines = fil.read()
        queryreg = re.compile('QUERY:fs:QUERY')
        textlines = queryreg.sub(query['fs'], textlines)
    except IOError:
        error = True

    if query['what'] == 'about':
        try:
            with open('legal/lgpl-3.0.txt', 'r') as fil:
                lgpl = fil.read()
            with open('legal/gpl.txt', 'r') as fil:
                gpl = fil.read()
            with open('html/availability.fmt', 'r') as fil:
                availability = fil.read()
        except IOError:
            error = True

    if query['what'] == 'corpus':
        try:
            with open('html/availability.fmt', 'r') as fil:
                # 补全原有业务逻辑
                pass
        except IOError:
            error = True

    if error:
        error_content = herigean()
        start_response('500 Internal Server Error', [('Content-Type', 'text/html')])
        return [error_content.encode('utf-8')]
    else:
        start_response('200 OK', [('Content-Type', 'text/html')])
        return [frontmatter.encode('utf-8')]

6. 调整跳转逻辑

原index.html的跳转指向display.py,在WSGI部署后,需要修改跳转地址为WSGI应用的挂载路径,比如如果应用挂载在根路径,修改为:

<meta http-equiv="Refresh" content="0;url=/what=index" />

或保持原有参数格式:

<meta http-equiv="Refresh" content="0;url=/display?what=index" />

具体路径取决于mod_wsgi的配置。


内容的提问来源于stack exchange,提问作者HBMCS

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 08:14:54