1.2GHz的机器上执行Red Hat Linux 7.3。使用4种类型的脚本。基于标准的CGI导入模块(以典型的Python
CGI脚本開始),然后输出'Hello!',測试10000次请求作为基准。
标准CGI: 23 次请求/秒
mod_python CGI处理器: 385 次请求/秒
mod_python 公布处理器: 476 次请求/秒
mod_python 处理器: 1203 次请求/秒
[root@www mod_python-3.3.1]# ls
configure CREDITS doc-html lib NEWS src
configure.in dist examples LICENSE NOTICE test
COPYRIGHT Doc install-sh Makefile.in README
[root@www mod_python-3.3.1]# find / -name apxs
/usr/sbin/apxs
[root@www mod_python-3.3.1]# ./configure --with-apxs=/usr/sbin/apxs
假设在编译的过程中出现了例如以下错误:
connobject.c:142: error: request for member ?.ext?
.in something not a structure or union
apxs:Error: Command failed with rc=65536
make[1]: *** [mod_python.so] Error 1
make[1]: Leaving directory `/usr/local/src/mod_python-3.3.1/src'
make: *** [do_dso] Error 2
须要改动/mod_python-3.3.1/src/connobject.c这个文件。将当中的“!(b == APR_BRIGADE_SENTINEL(b) ”
改动为 “!(b == APR_BRIGADE_SENTINEL(bb)”
/usr/lib/httpd/modules/mod_python.so
/usr/local/mod_python-3.3.1/src/.libs/mod_python.so
/usr/local/mod_python-3.3.1/src/mod_python.so
[root@www mod_python-3.3.1]#
然后检查apache的modules文件夹是否存在mod_python.so库。假设不存在,拷贝/usr/local/src/mod_python-3.3.1/src/mod_python.so到apache的modules文件夹。
并在httpd.conf中增加:
LoadModule python_module modules/mod_python.so
3.測试
配置httpd.conf文件
在httpd.conf中增加:
<Directory "/var/www/html/pyweb">
AllowOverride FileInfo
AddHandler mod_python .py
PythonHandler index
PythonDebug On
Order allow,deny
Allow from all
</Directory>
index 指定了模块名
#!/usr/bin/python
from mod_python import apache
def handler(req):
req.content_type='text/plain'
req.write("Hello, world!")
[root@www pyweb]#
解释一下这个程序:
addHandler 指示告诉 apache, 全部在/var/www/html/pyweb 文件夹或者是它的子文件夹下的全部.py文件,有关于这些文件的不论什么请求都用mod_python 来处理, PythonHandler
index 指示告诉 mod_python 用 index 运行默认的处理器. “pythonDebug On” 指示告诉mod_python假设错误发生。就把错误打印信息到client (相对于写入日志文件),在开发的时候这个选项很实用。
当一个请求发出时,apache通过调用mod_python中的处理器分步处理请求,Mod_python首先检查请求的那个处理器是否在配置文件里指定了(记住,它的角色是发报机dispatcher),在我们的样例中,mod_python除了调用默认的那个处理器外不会调用其它的不论什么处理器,然后,mod_python会发现"PythonHandler index "指示,并依照以下的步骤来进行:
1.假设曾经没有做过。那么就把pythonHandler指定的那个文件夹加到sys.path中。
2.尝试引入index 的模块(注意,假设index 在pythonHandler指定那个文件夹的子文件夹中的话,引入会出错,由于子文件夹并没有加到sys.path中,解决这样的情况的方法是使用包)比如:”pythonHandler
subdir.index ”
3.在index 中寻找名字叫handler的方法。
4.调用这种方法,并把request对象传递给它。
5.如今让我们深入这段脚本看一下:
from mod_python import apache
这个引入语句提供给我们一个訪问apache的接口。
除了极少数情况外,每个mod_python程序一般都会有这一行。
def handler(req):
这是处理器方法的声明,它之所以叫"handler"是由于mod_python在指示中使用这个名字,转换它为小写并移除"python",所以"pythonHandler"变成了"handler",你能够给它起别的名字,而且通过在指示中使用"::"明白的指定它.举个样例,假设处理器方法叫"spam",那么指示就应该是”pythonHandler myscript::spam”。
注意处理器必须有一个參数
request对象。Request对象提供了全部可能用到的信息。比方client的IP,头,URI等等.返回client的信息仍然通过request对象传递。注意,在mod_python中没有response对象。
req.content_type = "text/plain"
这条语句设置文档类型为” text/plain”。默认的一般是” text/html”,可是由于我们的处理器不处理不论什么html, 所以“text/plain”更合适一些。
req.write("Hello World!")
这条语句把字符串” Hello World!”写到client(再次强调没有response对象,所以写到client仍然有request对象)。
return apache.OK
这条语句告诉apache一切正常,并且请求也已经被处理了。假设出现异常,这一行应该返回apache.HTTP INTERNAL SERVER ERROR或返回apache.HTTP FORBIDDEN。并且apache会在日志中记录这个错误。并产生一条错误信息给client。
一些提示:假设你细致阅读的话,就会发现URI仅仅是指向了index.py这个文件,并没有指定处理器代码运行的顺序,实际上仅仅要告诉处理器须要处理的是一个.py文件就能够了。文件的名字并不重要,即使URL中指向的文件并不存在.所以,对于上面的配置。http://myserver/mywebdir/index.py 和 http://myserver/mywebdir/test.py 运行的结果是一样的。
IndentationError: expected an indented block
于是认为是config文件里 PythonHandler index的影响,去掉该行之后无法解析了。
AddHandler mod_python .py
PythonHandler index
PythonDebug On
编写mod_python程序在非常多方面和编写CGI程序类似。所以熟悉CGI(详见第18章)会对您学习mod_python有非常大的帮助。
mod_python和CGI之间也有不同的地方。在本章中。我们也将介绍这些不同。 19.1 理解为什么须要mod_python 我们已经在第18章中讨论过,CGI脚本是最经常使用的一种产生动态网页的方法。每当有页面请求的时候,相应的CGI脚本就被调用。它读取请求,产生应答,并终于终止。这是仿效HTTP的操作,后者的核心是一次为一个单一的请求服务。
下一次又有请求的时候。CGI脚本会被又一次调用。这种设计就使CGI脚本具有语言和server中立的特性;并且其实,全部流行的Webserver和程序语言都支持CGI。
然而,这样的兼容性是有代价的:那就是性能。
启动一个CGI脚本非常慢,操作系统须要为它建立新进程。Python解释器须要初始化和加载脚本。对于连接数据库的CGI脚本来说,性能就更差了,由于每次显示一个页面的时候,它们都必须建立一个新的数据库session。正是由于这个原因。CGI脚本不适合那些流量大的网站。 mod_python就是一个解决问题的方法。它实际上在Apache Webserver中嵌入了一个完整的Python解释器。
CGI脚本仅仅在server进程初始化的时候加载一次。
数据库连接也能够在Webserver初始化的时候建立,并保持连接直到Webserver关闭。每当要产生一个页面的时候,一个特殊的函数就被调用,全部关于请求的数据都被传入该函数。
这个函数有权訪问Webserver初始化时建立的环境变量。比如,它能够反复使用已经存在的数据库连接。
虽然这样的方法必须使用Apacheserver,可是它的长处要比缺点多得多,尤其是当您从头開始设计一个完整的Web应用的时候。
Python能够作为那些专门开发Web应用语言的替代者。比如PHP。 其实,mod_python除了用在提供页面之外还能够做其它的事情。它还能够在多个方面和Apache系统结合。比如:Apache提供了多种认证的处理方法。这些方法能够使您依据一个包括username和password的文本文件或LDAP数据库来认证用户。
您能够使用mod_python来编写您自己的认证处理程序(也许它通过一个远程XML-RPCserver来验证),并随时在Apache中使用这个程序——即使是那些不是由Python代码产生的页面。
公布器(publisher)提供了公布mod_python标准模块的方式。须要在配置文件里增加例如以下配置:
[root@www pyweb]# tail -7 /etc/httpd/conf/httpd.conf
<Directory "/var/www/html/pyweb/">
AddHandler mod_python .py
PythonHandler mod_python.publisher
PythonDebug On
</Directory>
经測试发现能够同一时候多个 PythonHandler处理器一起使用。仅仅是结果都会出如今同一页面。例如以下便是publisher和index測试同一时候配置了PythonHandler的结果。
请填写以下的回馈表单:
<form action="form.py/email" method="POST">
username: <input type="text" name="name"><br>
电子邮件: <input type="text" name="email"><br>
意见: <textarea name="comment" rows=4 cols=20></textarea><br>
<input type="submit">
</form>
</html>
#-*- coding: UTF-8 -*-
import smtplib
from mod_python import apache
WEBMASTER = "webmaster" # webmaster e-mail
SMTP_SERVER = "localhost" # your SMTP server
def email(req, name, email, comment):
#确定用户提供了全部的參数
if not (name and email and comment):
return "A required parameter is missing,please go back and correct the error"
# 创建消息对话框
msg = """\
From: %s
Subject: feedback
To: %s
I have the following comment:
%s
Thank You,
%s
""" % (email, WEBMASTER, comment, name)
#发出信件
conn = smtplib.SMTP(SMTP_SERVER)
conn.sendmail(email, [WEBMASTER], msg)
conn.quit()
# 返回用户信息
s = """\
<html>
亲爱的%s,<br>
谢谢你的意见,我们会在最近与你联系.
</html>
""" % name
return s
Return-Path: <171285755@qq.com>
X-Original-To: webmaster
Delivered-To: webmaster@www.tqy.com
Received: from www.tqy.com (localhost [IPv6:::1])
by www.tqy.com (Postfix) with ESMTP id 292EE1617
for <webmaster>; Tue, 17 Jun 2014 14:29:18 +0800 (CST)
Message-Id: <20140617062918.292EE1617@www.tqy.com>
Date: Tue, 17 Jun 2014 14:29:18 +0800 (CST)
From: 171285755@qq.com
To: undisclosed-recipients:;
From: 171285755@qq.com
Subject: feedback
To: webmaster
I have the following comment:
试试
Thank You,
tqy-test
当用户点击确定button的时候。公布处理器就会调用form模块中的email方法,把表单中各个域的值做为email方法的參数传递给email方法,而且也会把request的对象req一并传递过去。
并非非要把req做为email方法的一个參数不可。假设你不须要它,能够省略掉。
公布处理器非常灵活,它仅仅会把那些在方法的參数列表中存在參数所相相应的域的值传递过去。
方法的返回值在浏览器中显示出来。
尽管公布处理器极大的简化了mod_python编程。可是mod_python所具有的强大功能却没有损失,由于公布处理器能够訪问到request对象,所以你能够做到与原生(native)mod_python处理器全然同样的事情。 举例来说:
通过req.headers能够自己定义头(header),通过抛出apache.SERVERERROR返回异常,通过req.write()和req.read()直接读写client等等。
错误:SyntaxError: Non-ASCII character '\xe7' in file
出现这样的错误的原因是程序中的编码出问题了。仅仅要在程序的最前面加上
#-*- coding: UTF-8 -*-
又一次保存就可以
如果我们想用password保护一个文件夹,用名字:spam,password:eggs来登陆。
首先,我们须要告诉apache当须要认证的时候去调用我们的认证处理器。我们通过在配置文件里增加pythonAuthenHandler来实现,例如以下:
AddHandler mod_python .py
#PythonHandler mod_python.publisher #加上该句则输入username和password之后报错无法找到myscript.py文件
PythonHandler myscript #我们在这里为两个不同的处理器指定了同样的脚本。这是能够的
PythonAuthenHandler myscript
PythonDebug On
AuthType Basic
AuthName "Restricted Area"
require valid-user
</Directory>
[root@www pyweb]#
[root@www pyweb]# cat myscript.py
from mod_python import apache
def authenhandler(req): #处理器方法的声明
req.content_type='text/plain'
pw = req.get_basic_auth_pw()
user = req.user
if user == "spam" and pw == "eggs":
return apache.OK
else:
return apache.HTTP_UNAUTHORIZED
def handler(req):
req.content_type='text/html'
req.write("Hello, world!---test")
return apache.OK
[root@www pyweb]#
pw = req.get_basic_auth_pw()
我们通过这一句代码得到password。http在传输验证password的时候一般以base64的编码进行传输,这种方法把它解析成字符串。
from random import choice
adjectives = ['beatiful','cruel']
%>
<html>
<head>
<title>hello</title>
</head>
<body>
<p>hello.<%=choice(adjectives)%> girl. my name is ***</p>
</body>
</html>
A <%
for i in range(3):
%>
merry.
<%
%>
merry christamas time.
hello.beatiful girl. my name is ***
A merry. merry. merry. merry christamas time.
1.2GHz的机器上执行Red Hat Linux 7.3。使用4种类型的脚本,基于标准的CGI导入模块(以典型的Python
CGI脚本開始)。然后输出'Hello!',測试10000次请求作为基准。
标准CGI: 23 次请求/秒
mod_python CGI处理器: 385 次请求/秒
mod_python 公布处理器: 476 次请求/秒
mod_python 处理器: 1203 次请求/秒
[root@www mod_python-3.3.1]# ls
configure CREDITS doc-html lib NEWS src
configure.in dist examples LICENSE NOTICE test
COPYRIGHT Doc install-sh Makefile.in README
[root@www mod_python-3.3.1]# find / -name apxs
/usr/sbin/apxs
[root@www mod_python-3.3.1]# ./configure --with-apxs=/usr/sbin/apxs
假设在编译的过程中出现了例如以下错误:
connobject.c:142: error: request for member ?.ext?.in something not a structure or union
apxs:Error: Command failed with rc=65536
make[1]: *** [mod_python.so] Error 1
make[1]: Leaving directory `/usr/local/src/mod_python-3.3.1/src'
make: *** [do_dso] Error 2
须要改动/mod_python-3.3.1/src/connobject.c这个文件。将当中的“!(b == APR_BRIGADE_SENTINEL(b) ”
改动为 “!(b == APR_BRIGADE_SENTINEL(bb)”
/usr/lib/httpd/modules/mod_python.so
/usr/local/mod_python-3.3.1/src/.libs/mod_python.so
/usr/local/mod_python-3.3.1/src/mod_python.so
[root@www mod_python-3.3.1]#
然后检查apache的modules文件夹是否存在mod_python.so库。假设不存在。拷贝/usr/local/src/mod_python-3.3.1/src/mod_python.so到apache的modules文件夹。
并在httpd.conf中增加:
LoadModule python_module modules/mod_python.so
3.測试
配置httpd.conf文件
在httpd.conf中增加:
<Directory "/var/www/html/pyweb">
AllowOverride FileInfo
AddHandler mod_python .py
PythonHandler index
PythonDebug On
Order allow,deny
Allow from all
</Directory>
index 指定了模块名
#!/usr/bin/python
from mod_python import apache
def handler(req):
req.content_type='text/plain'
req.write("Hello, world!")
[root@www pyweb]#
解释一下这个程序:
addHandler 指示告诉 apache, 全部在/var/www/html/pyweb 文件夹或者是它的子文件夹下的全部.py文件,有关于这些文件的不论什么请求都用mod_python 来处理, PythonHandler
index 指示告诉 mod_python 用 index 运行默认的处理器. “pythonDebug On” 指示告诉mod_python假设错误发生。就把错误打印信息到client (相对于写入日志文件),在开发的时候这个选项很实用。
当一个请求发出时,apache通过调用mod_python中的处理器分步处理请求,Mod_python首先检查请求的那个处理器是否在配置文件里指定了(记住。它的角色是发报机dispatcher),在我们的样例中,mod_python除了调用默认的那个处理器外不会调用其它的不论什么处理器,然后,mod_python会发现"PythonHandler index "指示,并依照以下的步骤来进行:
1.假设曾经没有做过,那么就把pythonHandler指定的那个文件夹加到sys.path中。
2.尝试引入index 的模块(注意,假设index 在pythonHandler指定那个文件夹的子文件夹中的话,引入会出错,由于子文件夹并没有加到sys.path中,解决这样的情况的方法是使用包)比如:”pythonHandler
subdir.index ”
3.在index 中寻找名字叫handler的方法。
4.调用这种方法,并把request对象传递给它。
5.如今让我们深入这段脚本看一下:
from mod_python import apache
这个引入语句提供给我们一个訪问apache的接口。除了极少数情况外,每个mod_python程序一般都会有这一行。
def handler(req):
这是处理器方法的声明,它之所以叫"handler"是由于mod_python在指示中使用这个名字,转换它为小写并移除"python",所以"pythonHandler"变成了"handler",你能够给它起别的名字。而且通过在指示中使用"::"明白的指定它.举个样例,假设处理器方法叫"spam",那么指示就应该是”pythonHandler myscript::spam”。
注意处理器必须有一个參数
request对象。Request对象提供了全部可能用到的信息,比方client的IP,头,URI等等.返回client的信息仍然通过request对象传递,注意。在mod_python中没有response对象。
req.content_type = "text/plain"
这条语句设置文档类型为” text/plain”。
默认的一般是” text/html”,可是由于我们的处理器不处理不论什么html, 所以“text/plain”更合适一些。
req.write("Hello World!")
这条语句把字符串” Hello World!”写到client(再次强调没有response对象,所以写到client仍然有request对象)。
return apache.OK
这条语句告诉apache一切正常,并且请求也已经被处理了。
假设出现异常,这一行应该返回apache.HTTP INTERNAL SERVER ERROR或返回apache.HTTP FORBIDDEN。并且apache会在日志中记录这个错误,并产生一条错误信息给client。
一些提示:假设你细致阅读的话。就会发现URI仅仅是指向了index.py这个文件,并没有指定处理器代码运行的顺序,实际上仅仅要告诉处理器须要处理的是一个.py文件就能够了,文件的名字并不重要,即使URL中指向的文件并不存在.所以,对于上面的配置,http://myserver/mywebdir/index.py 和 http://myserver/mywebdir/test.py 运行的结果是一样的。
IndentationError: expected an indented block
于是认为是config文件里 PythonHandler index的影响,去掉该行之后无法解析了。
AddHandler mod_python .py
PythonHandler index
PythonDebug On
编写mod_python程序在非常多方面和编写CGI程序类似。所以熟悉CGI(详见第18章)会对您学习mod_python有非常大的帮助。mod_python和CGI之间也有不同的地方,在本章中,我们也将介绍这些不同。 19.1 理解为什么须要mod_python 我们已经在第18章中讨论过。CGI脚本是最经常使用的一种产生动态网页的方法。每当有页面请求的时候,相应的CGI脚本就被调用。
它读取请求,产生应答,并终于终止。这是仿效HTTP的操作,后者的核心是一次为一个单一的请求服务。下一次又有请求的时候,CGI脚本会被又一次调用。这种设计就使CGI脚本具有语言和server中立的特性;并且其实,全部流行的Webserver和程序语言都支持CGI。
然而。这样的兼容性是有代价的:那就是性能。启动一个CGI脚本非常慢,操作系统须要为它建立新进程。Python解释器须要初始化和加载脚本。对于连接数据库的CGI脚本来说。性能就更差了,由于每次显示一个页面的时候,它们都必须建立一个新的数据库session。正是由于这个原因,CGI脚本不适合那些流量大的网站。 mod_python就是一个解决问题的方法。它实际上在Apache Webserver中嵌入了一个完整的Python解释器。CGI脚本仅仅在server进程初始化的时候加载一次。数据库连接也能够在Webserver初始化的时候建立,并保持连接直到Webserver关闭。
每当要产生一个页面的时候。一个特殊的函数就被调用,全部关于请求的数据都被传入该函数。这个函数有权訪问Webserver初始化时建立的环境变量。比如。它能够反复使用已经存在的数据库连接。
虽然这样的方法必须使用Apacheserver,可是它的长处要比缺点多得多,尤其是当您从头開始设计一个完整的Web应用的时候。Python能够作为那些专门开发Web应用语言的替代者。比如PHP。 其实,mod_python除了用在提供页面之外还能够做其它的事情。
它还能够在多个方面和Apache系统结合。比如:Apache提供了多种认证的处理方法。这些方法能够使您依据一个包括username和password的文本文件或LDAP数据库来认证用户。
您能够使用mod_python来编写您自己的认证处理程序(也许它通过一个远程XML-RPCserver来验证),并随时在Apache中使用这个程序——即使是那些不是由Python代码产生的页面。
公布器(publisher)提供了公布mod_python标准模块的方式。
须要在配置文件里增加例如以下配置:
[root@www pyweb]# tail -7 /etc/httpd/conf/httpd.conf
<Directory "/var/www/html/pyweb/">
AddHandler mod_python .py
PythonHandler mod_python.publisher
PythonDebug On
</Directory>
经測试发现能够同一时候多个 PythonHandler处理器一起使用。仅仅是结果都会出如今同一页面。例如以下便是publisher和index測试同一时候配置了PythonHandler的结果。
请填写以下的回馈表单:
<form action="form.py/email" method="POST">
username: <input type="text" name="name"><br>
电子邮件: <input type="text" name="email"><br>
意见: <textarea name="comment" rows=4 cols=20></textarea><br>
<input type="submit">
</form>
</html>
#-*- coding: UTF-8 -*-
import smtplib
from mod_python import apache
WEBMASTER = "webmaster" # webmaster e-mail
SMTP_SERVER = "localhost" # your SMTP server
def email(req, name, email, comment):
#确定用户提供了全部的參数
if not (name and email and comment):
return "A required parameter is missing,please go back and correct the error"
# 创建消息对话框
msg = """\
From: %s
Subject: feedback
To: %s
I have the following comment:
%s
Thank You,
%s
""" % (email, WEBMASTER, comment, name)
#发出信件
conn = smtplib.SMTP(SMTP_SERVER)
conn.sendmail(email, [WEBMASTER], msg)
conn.quit()
# 返回用户信息
s = """\
<html>
亲爱的%s,<br>
谢谢你的意见,我们会在最近与你联系.
</html>
""" % name
return s
Return-Path: <171285755@qq.com>
X-Original-To: webmaster
Delivered-To: webmaster@www.tqy.com
Received: from www.tqy.com (localhost [IPv6:::1])
by www.tqy.com (Postfix) with ESMTP id 292EE1617
for <webmaster>; Tue, 17 Jun 2014 14:29:18 +0800 (CST)
Message-Id: <20140617062918.292EE1617@www.tqy.com>
Date: Tue, 17 Jun 2014 14:29:18 +0800 (CST)
From: 171285755@qq.com
To: undisclosed-recipients:;
From: 171285755@qq.com
Subject: feedback
To: webmaster
I have the following comment:
试试
Thank You,
tqy-test
当用户点击确定button的时候。公布处理器就会调用form模块中的email方法。把表单中各个域的值做为email方法的參数传递给email方法,而且也会把request的对象req一并传递过去。
并非非要把req做为email方法的一个參数不可。假设你不须要它,能够省略掉。公布处理器非常灵活。它仅仅会把那些在方法的參数列表中存在參数所相相应的域的值传递过去。
方法的返回值在浏览器中显示出来。
尽管公布处理器极大的简化了mod_python编程。可是mod_python所具有的强大功能却没有损失,由于公布处理器能够訪问到request对象,所以你能够做到与原生(native)mod_python处理器全然同样的事情。
举例来说:
通过req.headers能够自己定义头(header)。通过抛出apache.SERVERERROR返回异常,通过req.write()和req.read()直接读写client等等。
错误:SyntaxError: Non-ASCII character '\xe7' in file
出现这样的错误的原因是程序中的编码出问题了。仅仅要在程序的最前面加上
#-*- coding: UTF-8 -*-
又一次保存就可以
如果我们想用password保护一个文件夹,用名字:spam,password:eggs来登陆。
首先,我们须要告诉apache当须要认证的时候去调用我们的认证处理器。我们通过在配置文件里增加pythonAuthenHandler来实现,例如以下:
AddHandler mod_python .py
#PythonHandler mod_python.publisher #加上该句则输入username和password之后报错无法找到myscript.py文件
PythonHandler myscript #我们在这里为两个不同的处理器指定了同样的脚本,这是能够的
PythonAuthenHandler myscript
PythonDebug On
AuthType Basic
AuthName "Restricted Area"
require valid-user
</Directory>
[root@www pyweb]#
[root@www pyweb]# cat myscript.py
from mod_python import apache
def authenhandler(req): #处理器方法的声明
req.content_type='text/plain'
pw = req.get_basic_auth_pw()
user = req.user
if user == "spam" and pw == "eggs":
return apache.OK
else:
return apache.HTTP_UNAUTHORIZED
def handler(req):
req.content_type='text/html'
req.write("Hello, world!---test")
return apache.OK
[root@www pyweb]#
pw = req.get_basic_auth_pw()
我们通过这一句代码得到password。
http在传输验证password的时候一般以base64的编码进行传输,这种方法把它解析成字符串。
from random import choice
adjectives = ['beatiful','cruel']
%>
<html>
<head>
<title>hello</title>
</head>
<body>
<p>hello.<%=choice(adjectives)%> girl. my name is ***</p>
</body>
</html>
A <%
for i in range(3):
%>
merry.
<%
%>
merry christamas time.
hello.beatiful girl. my name is ***
A merry. merry. merry. merry christamas time.
版权声明:本文博主原创文章,博客,未经同意不得转载。