我可以在 App Engine 上使用我最喜欢的框架吗?
App Engine 运行时环境强加了一些约束,以确保可在 App Engine 的分布式基础架构上将应用程序扩展为多个实例。许多框架可在 App Engine 服务器运行时环境内实现无缝工作,但有些不能。其他的可能需要进行某些修改。
因为存在大量的框架,因此我们使用面向社区的方法在此处提供了一个协作页面:是否可在 App Engine 中运行 (Will it Play in App Engine)。请搜索该页面以检查您最喜欢的框架的状态,如果未列出您的框架或您有更新或修正,请提交评论。
我可以在 App Engine 应用程序中使用哪些 JVM 语言?
许多设计为可在 JVM 中运行的语言(如 JRuby、Jython、Scala 以及 Groovy 等)都可在 App Engine 上使用。目前并不是所有这些语言都经过了完整的测试,因此我们使用面向社区的方法在此处提供了一个协作页面:是否可在 App Engine 中运行 (Will it Play in App Engine)。请在测试过您选择的运行时语言后添加相关信息。
为什么我不能从该文件读取?
如果作为应用程序的一部分上传的文件位于以下位置,则可从该文件读取:
- war/WEB-INF
- 与 appengine-web.xml 中的 <resource-files> 模式匹配的位置(默认情况下包括一切)
如果文件位置没有问题,则问题可能是您用于从文件读取的方法未列入白名单。您的应用程序可使用任何可用于从文件系统读取的 IO 类,例如 File
、FileInputStream
、FileReader
或 RandomAccessFile
。有关白名单上列出的类的完整列表,请参阅 JRE 类白名单。
如果您需要获得您自己的资源(如属性文件)的文件访问权限,可将这些文件放入 jar 中,并使用 Class
或 ClassLoader
将其载入。
为什么我不能写入到该文件?
由于应用程序的分布式性质,在 App Engine 中不支持写入到本地文件。因此,应将必须保存的数据存储在分布式数据存储区中。有关详细信息,请参阅关于运行时沙盒的文档。
我可以在应用程序中创建新线程吗?
不可以,App Engine 应用程序无法生成新线程。有关详细信息,请参阅关于运行时沙盒的文档。
我有现有的 Python 应用程序,可以访问现有的 Python 数据存储区吗?
可以,可将 Java 代码上传到您的应用程序(建议指定一个新的版本号),然后您的 Java 代码即可访问数据存储区中的数据。类型名称和属性名称在不同的语言间是一致的。
请注意确保能够将 Python 模型实体中使用的数据类型载入 Java 代码中。
我可以在同一应用程序中运行 Java 和 Python 代码吗?
可以,应用程序的各个版本都必须指定运行时语言,因此可以实现版本 x 运行 Java,而版本 y 运行 Python。还可以使用 Jython。
为什么在试图登录应用程序时会出现 UserServiceFailureException?
如果您将应用程序与 Google 企业应用套件域相关联,则必须在 Google 企业应用套件帐户的子域上访问该应用程序。例如,如果 example.com 是您的 Google 企业应用套件域,则您必须创建一个子域(在此例中使用 www)并将其指向 App Engine 上运行的应用程序。然后您可以从 www.example.com 登录到您的应用程序。如果您尝试通过 app-id.appspot.com 网址访问应用程序,则将无法使用 Google 企业应用套件帐户登录。本限制仅对限制到 Google 企业应用套件域的应用程序适用。
我看到所有请求处理程序均出现初始化失败异常。
您的某个过滤条件、servlet 或 JSP 可能出现错误,阻止了应用程序中所有处理程序的正常初始化。
如果预编译 JSP,可能会引发初始化问题。作为更新过程的一部分,appcfg 命令可为您预编译 JSP,因此您不必进行预编译。
如果出于某种原因需要自己对它们进行预编译,则解决方法是把所有的 JSP 库与应用程序捆绑在一起。其中包括:
- Jasper 运行时和编译器(假设您使用其进行预编译)。
- 所有所需的标签库(包括 JSTL)。
- EL 实现(如果您要使用它)。
在 appcfg 执行离线 JSP 编译的过程中,会将这些库添加到每个应用程序,因此,如果您要自己进行 JSP 编译,则需要做同样的事情。
如果您有使用 Jasper 的预编译 JSP,则必须在 WEB-INF/lib 中包含以下 jar:
- commons-logging-api-1.1.1.jar(或更高版本)
- commons-el.jar
- jasper-runtime.jar
请注意,实际上即使您未使用 EL 和 logging,它们也是必需的。
App Engine 是否支持 Java 企业版?
虽然我们不支持全部 Java EE 规范,但支持其中很多单个组件。有关特定的支持组件和不支持组件列表,请参阅我们用于跟踪框架、语言和库兼容性的协作编辑页面:是否可在 App Engine 中运行 (Will it Play in App Engine)。
如何处理多部分格式数据?或如何处理应用程序的文件上传?
您可以使用 Apache Commons 文件上传包中的类从多部分格式发布中获取上传的文件数据。特别是,您可以如下使用 FileItemStream
、FileItermIterator
和 ServletFileUpload
。
import org.apache.commons.fileupload.FileItemStream; import org.apache.commons.fileupload.FileItemIterator; import org.apache.commons.fileupload.servlet.ServletFileUpload; import java.io.InputStream; import java.io.IOException; import java.util.logging.Logger; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class FileUpload extends HttpServlet { private static final Logger log = Logger.getLogger(FileUpload.class.getName()); public void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { try { ServletFileUpload upload = new ServletFileUpload(); res.setContentType("text/plain"); FileItemIterator iterator = upload.getItemIterator(req); while (iterator.hasNext()) { FileItemStream item = iterator.next(); InputStream stream = item.openStream(); if (item.isFormField()) { log.warning("Got a form field: " + item.getFieldName()); } else { log.warning("Got an uploaded file: " + item.getFieldName() + ", name = " + item.getName()); // You now have the filename (item.getName() and the // contents (which you can read from stream). Here we just // print them back out to the servlet output stream, but you // will probably want to do something more interesting (for // example, wrap them in a Blob and commit them to the // datastore). int len; byte[] buffer = new byte[8192]; while ((len = stream.read(buffer, 0, buffer.length)) != -1) { res.getOutputStream().write(buffer, 0, len); } } } } catch (Exception ex) { throw new ServletException(ex); } } }
我一直使用端口 8080,如何更改开发应用程序服务器的端口?
如果您看到以下错误消息:
Could not open the requested socket: Address already in use
您可以更改开发服务器监听传入连接的端口。可通过以下参数设置端口:
--port=desired-port-number
如果您使用的是带有 dev_appserver
元素的 ant 目标,则可通过如下方式添加 port
属性指定端口参数。
<dev_appserver war="war" port="desired-port-number"/>
我可以在 App Engine 上使用 Google 数据 API 库吗?
可以,Google 数据 Java 客户端库可在 App Engine 中使用,但必须设置配置选项,以免发生运行时权限错误。请将以下内容添加到 appengine-web.xml
文件:
<system-properties> <property name="com.google.gdata.DisableCookieHandler" value="true"/> </system-properties>
如果未包括以上内容,则可能会出现以下异常:
java.security.AccessControlException: access denied (java.net.NetPermission getCookieHandler)
Eclipse 插件不能正常运行。
如果您遇到 Google Eclipse 插件或 Eclipse 本身相关的意外问题,可从查看“错误日志”视图开始解决问题。在 Eclipse 菜单上选择“窗口”->“显示视图”->“其他...”,然后选择“常规”->“错误日志”。可双击各个条目以获取详细信息。此外,还可在名为 your-eclipse-workspace-directory/.metadata/.log
的文件中找到这些问题的文本版本。
我在试图上传时收到“指定的运行时无效”。
在试图使用 appcfg 更新应用程序时,服务器将检查您的帐户以查看您是否有权上传使用 Java 运行时的应用程序。如果您的帐户没有权限,将会显示下列错误消息:
java.io.IOException: Error posting to URL: http://appengine.google.com/api/appversion/... 400 Bad Request Invalid runtime specified. Unable to upload app: Error posting to URL: http://appengine.google.com/api/appversion/... 400 Bad Request Invalid runtime specified.
要请求获得上传使用 Java 运行时的应用程序的权限,请在以下网址注册:http://appengine.google.com/promo/java_runtime。目前,访问权限仅限于前 10000 个注册的帐户。
appcfg 中的电子邮件参数似乎无法工作。
必须在进行 appcfg 操作之前指定电子邮件命令行参数。例如,下列命令是正确的:
appcfg.sh -e youremail@example.com update app_directory/war