lizongbo at 618119.com 工作,生活,Android,前端,Linode,Ubuntu,nginx,java,apache,tomcat,Resin,mina,Hessian,XMPP,RPC

2009年04月11日

使用Google App Engine的URLFetchService实现类似phpproxy访问页面

Filed under: Java — 标签:, , — lizongbo @ 00:00

使用Google App Engine的URLFetchService实现类似phpproxy访问页面,
今天接着体验google appEngine,参考文档写了个类似phpproxy以代理方式获取页面内容的Servlet。
phpproxy的功能很强大,我的程序很简单,只实现了简单的获取页面内容然后显示。
phpproxy的代码在:http://idea.hosting.lv/a/phpproxy/phpproxy-0.6/phpproxy.phps
我的页面在:
http://lizongbo.appspot.com/p?url=http://www.google.cn
URLFetchService的介绍在:http://code.google.com/intl/zh-CN/appengine/docs/java/urlfetch/

首先,web.xml的配置是:

[code]
</servlet-mapping>
<servlet>
<servlet-name>HttpProxy</servlet-name>
<servlet-class>com.lizongbo.gapp.HttpProxyServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>HttpProxy</servlet-name>
<url-pattern>/p</url-pattern> <!– 写成/p/*居然没法匹配到/p–>
</servlet-mapping>
[/code]
com.lizongbo.gapp.HttpProxyServlet.java的代码为:

[code]
package com.lizongbo.gapp;

import .io.IOException;
import java.io.PrintWriter;
import java.net.URL;
import java.util.Enumeration;
import java.util.Map;

import javax.servlet.http.*;

import com.google.appengine.api.urlfetch.*;

@SuppressWarnings(“serial”)
public class HttpProxyServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException {
String urlStr = request.getParameter(“url”);
java.net.URL url = null;
try {
url = new URL(urlStr);
if (!url.getHost().toLowerCase().endsWith(“appspot.com”)//不需代理本站
&& url.getPort() == url.getDefaultPort()) {//google限制了只能访问默认端口
URLFetchService urlFetchService = URLFetchServiceFactory
.getURLFetchService();
HTTPRequest req = new HTTPRequest(url, HTTPMethod.GET);
req.addHeader(new HTTPHeader(“X-Fetchby”,
http;//lizongbo.appsport.com“));
HTTPResponse res = urlFetchService.fetch(req);
response.setStatus(res.getResponseCode());
response.reset();
response.addHeader(“X-powerby”, “http://lizongbo.appsport.com“);
for (HTTPHeader header : res.getHeaders()) {
response.addHeader(header.getName(), header.getValue());
}
response.getOutputStream().write(res.getContent());
} else {
response.setContentType(“text/plain; charset=UTF-8”);
response.getWriter().write(
“url 不能是appspot.com,http请求端口必须是默认的80(http)和443(https)”);
}
} catch (Throwable ex) {
response.setContentType(“text/html; charset=UTF-8”);
ex.printStackTrace(new java.io.PrintWriter(response.getWriter()));
}

}
}

[/code]

在localhost方式访问某测试页面看到的请求信息为:
X-Fetchby=http;//lizongbo.appsport.com
User-Agent=Jakarta Commons-HttpClient/3.0.1
Host=3g.qq.com
部署到lizongbo.appspot.com之后访问看到的header信息:
X-Fetchby=http;//lizongbo.appsport.com
User-Agent=AppEngine-Google; (+http://code.google.com/appengine)
Referer=http://lizongbo.appspot.com/
Host=3g.qq.com
Accept-Encoding=gzip

上面的代码如果是在jsp里实现,
会因为Writer和ServletOutPutStream不能同时get而跑出异常,即使response.reset也没用。
异常信息如下:

[code]
java.lang.IllegalStateException: STREAM
at org.mortbay.jetty.Response.getWriter(Response.java:583)
at org.apache.jasper.runtime.JspWriterImpl.initOut(JspWriterImpl.java:122)
at org.apache.jasper.runtime.JspWriterImpl.flushBuffer(JspWriterImpl.java:115)
at org.apache.jasper.runtime.PageContextImpl.release(PageContextImpl.java:190)
at org.apache.jasper.runtime.JspFactoryImpl.internalReleasePageContext(JspFactoryImpl.java:115)
at org.apache.jasper.runtime.JspFactoryImpl.access$100(JspFactoryImpl.java:37)
at org.apache.jasper.runtime.JspFactoryImpl$PrivilegedReleasePageContext.run(JspFactoryImpl.java:173)
at com.google.apphosting.runtime.security.shared.intercept.java.security.AccessController_.doPrivileged(AccessController_.java:31)
at org.apache.jasper.runtime.JspFactoryImpl.releasePageContext(JspFactoryImpl.java:73)
at org.apache.jsp.proxy_jsp._jspService(p_jsp.java:82)
at org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:94)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:802)
at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:487)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1093)
at com.google.apphosting.runtime.jetty.SaveSessionFilter.doFilter(SaveSessionFilter.java:35)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1084)
at com.google.apphosting.utils.servlet.TransactionCleanupFilter.doFilter(TransactionCleanupFilter.java:43)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1084)
at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:360)
at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)
at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:181)
at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:712)
at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:405)
at com.google.apphosting.runtime.jetty.AppVersionHandlerMap.handle(AppVersionHandlerMap.java:237)
at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:139)
at org.mortbay.jetty.Server.handle(Server.java:313)
at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:506)
at org.mortbay.jetty.HttpConnection$RequestHandler.headerComplete(HttpConnection.java:830)
at com.google.apphosting.runtime.jetty.RpcRequestParser.parseAvailable(RpcRequestParser.java:63)
at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:381)
at com.google.apphosting.runtime.jetty.JettyServletEngineAdapter.serviceRequest(JettyServletEngineAdapter.java:125)
at com.google.apphosting.runtime.JavaRuntime.handleRequest(JavaRuntime.java:235)
at com.google.apphosting.base.RuntimePb$EvaluationRuntime$6.handleBlockingRequest(RuntimePb.java:4547)
at com.google.apphosting.base.RuntimePb$EvaluationRuntime$6.handleBlockingRequest(RuntimePb.java:4545)
at com.google.net.rpc.impl.BlockingApplicationHandler.handleRequest(BlockingApplicationHandler.java:24)
at com.google.net.rpc.impl.RpcUtil.runRpcInApplication(RpcUtil.java:359)
at com.google.net.rpc.impl.Server$2.run(Server.java:792)
at com.google.tracing.LocalTraceSpanRunnable.run(LocalTraceSpanRunnable.java:56)
at com.google.tracing.LocalTraceSpanBuilder.internalContinueSpan(LocalTraceSpanBuilder.java:489)
at com.google.net.rpc.impl.Server.startRpc(Server.java:748)
at com.google.net.rpc.impl.Server.processRequest(Server.java:340)
at com.google.net.rpc.impl.ServerConnection.messageReceived(ServerConnection.java:422)
at com.google.net.rpc.impl.RpcConnection.parseMessages(RpcConnection.java:319)
at com.google.net.rpc.impl.RpcConnection.dataReceived(RpcConnection.java:290)
at com.google.net.async.Connection.handleReadEvent(Connection.java:419)
at com.google.net.async.EventDispatcher.processNetworkEvents(EventDispatcher.java:733)
at com.google.net.async.EventDispatcher.internalLoop(EventDispatcher.java:207)
at com.google.net.async.EventDispatcher.loop(EventDispatcher.java:101)
at com.google.net.rpc.RpcService.runUntilServerShutdown(RpcService.java:249)
at com.google.apphosting.runtime.JavaRuntime$RpcRunnable.run(JavaRuntime.java:373)
at java.lang.Thread.run(Unknown Source)

[/code]

Google App Engine的war文件夹里,我放了favicon.ico。但是不知为何却没到服务器上,导致后台老是看到访问favicon.ico的404错误。

另:google app engine说是支持Servlet 2.4,但是通过插件默认生成的web.xml里

dtd的引用是 http://java.sun.com/dtd/web-app_2_3.dtd

而web-app的属性声明里version的值却是2.5。

web Project引用的lib也是 /usr/local/java/appengine-java-sdk-1.2.0/lib/shared/geronimo-servlet_2.5_spec-1.2.jar。猜测应该是支持Servlet 2.5的。

一条评论 »

  1. 想用GAE实现HTTP Basic authentication,前辈可否给个思路。。多谢。不知道评论有没有邮件提醒,我的邮箱是dracy@ubuntusky.cn。。

    Reply

    评论 by Dracy — 2009年04月14日 @ 13:17

RSS feed for comments on this post. TrackBack URL

Leave a comment

Powered by WordPress