Android系统上部署webservice

时间:2023-01-10 13:25:06

1.前期技术选型

用android系统做服务器,我相信做的人真不多。经过搜索,我首先找到的是i-jetty.这是jetty经过交叉编译移植到android平台的web服务器软件,它可以部署web网站。但这不是我想要的,第一,它太大了,第二,二次开发比较困难。因此我继续寻找简单的方法。首先我想到的是自己使用java依照http协议开发一个吧,于是写了一个小型的get,post请求的服务器,但由于水平原因,存在大量bug。这是我的方向就基本确定了,我需要的不是只有在android运行的服务器,而是要一个可以在纯java环境服务。终于,在stack overflow我找到了这个问题的解,NonoHTTPD,上面的人回答说very simple.第一直觉这就是我需要的。

2.了解NonoHTTPD

NonoHTTPD gitHub地址:https://github.com/NanoHttpd/nanohttpd
通过阅读readme文件,这是开发项目使用maven进行管理,core中NonoHTTPD.java是这项目的核心,only one file.真是太棒了。于是我把源码从github拉了下来,由于本地没用用maven,因此只是复制了NonoHTTPD.java文件和其example文件夹。运行了一下HelloServer,通过浏览器访问,果然成功了。

package fi.iki.elonen;

import java.util.Map;
import java.util.logging.Logger;

import fi.iki.elonen.util.ServerRunner;

/**
* An example of subclassing NanoHTTPD to make a custom HTTP server.
*/
public class HelloServer extends NanoHTTPD {

/**
* logger to log to.
*/
private static final Logger LOG = Logger.getLogger(HelloServer.class.getName());

public static void main(String[] args) {
ServerRunner.run(HelloServer.class);
}

public HelloServer() {
super(8080);
}

@Override
public Response serve(IHTTPSession session) {
Method method = session.getMethod();
String uri = session.getUri();
HelloServer.LOG.info(method + " '" + uri + "' ");

String msg = "<html><body><h1>Hello server</h1>\n";
Map<String, String> parms = session.getParms();
if (parms.get("username") == null) {
msg += "<form action='?' method='get'>\n" + " <p>Your name: <input type='text' name='username'></p>\n" + "</form>\n";
} else {
msg += "<p>Hello, " + parms.get("username") + "!</p>";
}

msg += "</body></html>\n";

return newFixedLengthResponse(msg);
}
}

通过看HelloServer类,我们可以看到,要实现自己的webservice,只需要继承NonoHTTPD和重写serve方法即可。IHTTPSession包含了请求的一切,我们只需对session处理并返回Response就行了。

3.开始编写属于自己的http服务器

按我的需求,主要是为了实现get和post请求。

1.get请求

get请求的内容直接在url中,post请求的内容在正文中。一般get请求我们url的格式都是这样的:http://localhost:80/webservice?username=lilei&password=12345
我们从url中提取我们需要的信息。当然我们不需要重复造*,NonoHTTPD已经帮我们写好了,我们只要一行代码 Map<String, String> parms = session.getParms();就可以获取到了我们所需的内容。

2.post请求

通过Method method = session.getMethod();我们可以获取请求的方法,Method是枚举变量。先是我很疑惑session无法获取正文内容,只有session.getinputstream可以。这未免有点麻烦。因此我阅读了NonoHTTPD的源码,发现源码中有body处理的方法。

    Map<String, String> files = new HashMap<String, String>();
try {
session.parseBody(files);
} catch (IOException ioe) {
return newFixedLengthResponse(Response.Status.INTERNAL_ERROR, NanoHTTPD.MIME_PLAINTEXT, "SERVER INTERNAL ERROR: IOException: " + ioe.getMessage());
} catch (ResponseException re) {
return newFixedLengthResponse(re.getStatus(), NanoHTTPD.MIME_PLAINTEXT, re.getMessage());
}
String parameter = files.get("postData");
System.out.println(parameter);

只需要取出postData,String parameter = files.get("postData");就是我们需要的正文了。(我们将使用json进行数据传输)。这样我们自定义的webserver只需要打包成依赖包,添加到我们的android项目,并启动,就可以在外面访问,并控制android设备了。

4.问题与扩展

我看到源码中有了很多测试代码,相信核心不会有问题了,但是在实际运行的时候,我又发现了一个问题:但不在本地访问时,速度非常慢,基本是10.26s左右。这10s应该是超时的时候或在哪睡眠的时间吧。经过一个debug,我在NonoHTTPD找到了可恶的一行代码:inetAddress.getHostName().toString();这行代码是反向查找客户端主机名,如果本地没有这主机名和ip的映射,那将是相当慢的。因此我毫不犹豫的注释掉了这行代码。(过后得问问他们团队是怎么想的才行)。

扩展:对url请求的进行分发给不同的类处理,这些类共同实现一个action接口。方便不断添加的不同处理需要。我实现了一个小框架,将于下节再说。