在 Android 设备上搭建 Web 服务器

叶志陈已关注

12018.04.11 00:20:05字数 1,018阅读 10,291

一般而言,Android 应用在请求数据时都是以 Get 或 Post 等方式向远程服务器发起请求,那你有没有想过其实我们也可以在 Android 设备上搭建一个小型 Web 服务器,并且实现常规的下载图片、下载文件、提交表单等功能呢?
下面要介绍的就是如何在 Android 设备上搭建一个 Web 服务器,这个 Web 服务器的功能有如下几点:

  1. 接受客户端文件上传、下载文件
  2. 动态 Http API,像 Java 的 Servlet 一样写接口
  3. 部署静态网站,例如纯Html,支持 JS、CSS、Image 分离
  4. 部署动态网站

这需要依赖一个开源库来实现:AndServer

AndServer 类似于 Apache 和 Tomcat,支持在同个局域网下的设备能够以常规的网络请求方式来向 Web 服务器请求数据,只要指明 Web 服务器的 IP 地址和端口号即可

那么,这个 Web 服务器的用途有哪些呢?

说下我现在遇到的一个需求吧!需要实现两台设备(Android 或 ios 设备)在无网络情况下进行数据交流。本来是打算让设备之间的交流通道以 Wifi 来链接,即某一台设备连上另一台设备的 Wiif 热点,这样两者之间就建立起了一条“通道”,之后通过建立 Socket 连接来获取输入输出流,通过输入输出流来交换数据。可是这样就需要处理好在高并发情况下的数据同步和解析问题,比较麻烦,而通过 AndServer 就可以直接套用项目已有的网络请求框架,直接以网络请求的方式来交流数据,而服务端也较好的处理了并发问题

Gradle 远程依赖

implementation 'com.yanzhenjie:andserver:1.1.3'

搭建服务器

搭建服务器的方式很简单,支持链式调用。指明服务器在本机的 IP 地址上监听,并指定端口号为 1995 ,并开放了三个接口分别用于:下载文件、下载图片、Post表单

       AndServer server = AndServer.serverBuilder().inetAddress(NetUtils.getLocalIPAddress())  //服务器要监听的网络地址.port(Constants.PORT_SERVER) //服务器要监听的端口.timeout(10, TimeUnit.SECONDS) //Socket超时时间.registerHandler(Constants.GET_FILE, new DownloadFileHandler()) //注册一个文件下载接口.registerHandler(Constants.GET_IMAGE, new DownloadImageHandler()) //注册一个图片下载接口.registerHandler(Constants.POST_JSON, new JsonHandler()) //注册一个Post Json接口.filter(new HttpCacheFilter()) //开启缓存支持.listener(new Server.ServerListener() {  //服务器监听接口@Overridepublic void onStarted() {String hostAddress = server.getInetAddress().getHostAddress();Log.e(TAG, "onStarted : " + hostAddress);ServerPresenter.onServerStarted(ServerService.this, hostAddress);}@Overridepublic void onStopped() {Log.e(TAG, "onStopped");ServerPresenter.onServerStopped(ServerService.this);}@Overridepublic void onError(Exception e) {Log.e(TAG, "onError : " + e.getMessage());ServerPresenter.onServerError(ServerService.this, e.getMessage());}}).build();

开启服务器

server.startup();

停止服务器

server.shutdown();

接口处理器

在注册接口时,除了指明开放出来的 Url 地址外,还需要指明相应的处理器,专门用于处理该接口的请求操作
开放出来的三个接口分别对应于三个地址

public class Constants {//服务端接口的端口号public static final int PORT_SERVER = 1995;public static final String GET_FILE = "/file";public static final String GET_IMAGE = "/image";public static final String POST_JSON = "/json";}
 ···.registerHandler(Constants.GET_FILE, new DownloadFileHandler()) //注册一个文件下载接口.registerHandler(Constants.GET_IMAGE, new DownloadImageHandler()) //注册一个图片下载接口.registerHandler(Constants.POST_JSON, new JsonHandler()) //注册一个Post Json接口···

例如,假设设备的 IP 地址是:192.168.0.101 ,那么在访问 http://192.168.0.101:1995/file 接口时,请求操作就会由 DownloadFileHandler 来处理

下载文件

DownloadFileHandler 实现了 RequestHandler 接口,在 handle 方法中可以获取到请求头,表单数据这些信息,,通过注解声明支持 Get 方式调用,在此直接返回一个文本文件用于下载

/*** 作者:leavesC* 时间:2018/4/5 16:30* 描述:https://github.com/leavesC/AndroidServer* https://www.jianshu.com/u/9df45b87cfdf*/
public class DownloadFileHandler implements RequestHandler {@RequestMapping(method = {RequestMethod.GET})@Overridepublic void handle(HttpRequest httpRequest, HttpResponse httpResponse, HttpContext httpContext) throws HttpException, IOException {File file = createFile();HttpEntity httpEntity = new FileEntity(file, ContentType.create(getMimeType(file.getAbsolutePath()), Charset.defaultCharset()));httpResponse.setHeader("Content-Disposition", "attachment;filename=File.txt");httpResponse.setStatusCode(200);httpResponse.setEntity(httpEntity);}private File createFile() {File file = null;OutputStream outputStream = null;try {file = File.createTempFile("File", ".txt", MainApplication.get().getCacheDir());outputStream = new FileOutputStream(file);outputStream.write("leavesC,这是一段测试文本".getBytes());} catch (IOException e) {e.printStackTrace();} finally {if (outputStream != null) {try {outputStream.flush();outputStream.close();} catch (IOException e) {e.printStackTrace();}}}return file;}}

这里直接在浏览器中访问接口(要和 Android Web服务器运行在同个局域网下),可以直接下载到文件

下载图片

类似的,下载图片的接口处理器 DownloadImageHandler 可以如下设计,在 handle 方法中返回应用的图标

/*** 作者:leavesC* 时间:2018/4/5 16:30* 描述:https://github.com/leavesC/AndroidServer* https://www.jianshu.com/u/9df45b87cfdf*/
public class DownloadImageHandler extends SimpleRequestHandler {private File file = new File(Environment.getExternalStorageDirectory(), "leavesC.jpg");@RequestMapping(method = {RequestMethod.GET})@Overrideprotected View handle(HttpRequest request) throws HttpException, IOException {writeToSdCard();HttpEntity httpEntity = new FileEntity(file, ContentType.create(getMimeType(file.getAbsolutePath()), Charset.defaultCharset()));return new View(200, httpEntity);}private void writeToSdCard() throws IOException {if (!file.exists()) {synchronized (DownloadImageHandler.class) {if (!file.exists()) {boolean b = file.createNewFile();if (!b) {throw new IOException("What broken cell phone.");}Bitmap bitmap = BitmapFactory.decodeResource(MainApplication.get().getResources(), R.mipmap.ic_launcher_round);OutputStream outputStream = null;try {outputStream = new FileOutputStream(file);bitmap.compress(Bitmap.CompressFormat.JPEG, 100, outputStream);} catch (FileNotFoundException e) {e.printStackTrace();} finally {if (outputStream != null) {outputStream.flush();outputStream.close();}}}}}}}

Post表单

这里需要将注解值改为 RequestMethod.POST,通过 HttpRequestParser.getContentFromBody(httpRequest) 函数可以获取到表单数据,这里直接检测表单数据是否为 Json 字符串,是的话则为之多添加一个属性 :"state" 作为返回值,否则返回只包含属性 “state” 的 Json 字符串

/*** 作者:leavesC* 时间:2018/4/5 16:30* 描述:https://github.com/leavesC/AndroidServer* https://www.jianshu.com/u/9df45b87cfdf*/
public class JsonHandler implements RequestHandler {@RequestMapping(method = {RequestMethod.POST})@Overridepublic void handle(HttpRequest httpRequest, HttpResponse httpResponse, HttpContext httpContext) throws HttpException, IOException {String content = HttpRequestParser.getContentFromBody(httpRequest);JSONObject jsonObject = null;try {jsonObject = new JSONObject(content);} catch (JSONException e) {e.printStackTrace();}if (jsonObject == null) {jsonObject = new JSONObject();}try {jsonObject.put("state", "success");} catch (JSONException e) {e.printStackTrace();}StringEntity stringEntity = new StringEntity(jsonObject.toString(), "utf-8");httpResponse.setStatusCode(200);httpResponse.setEntity(stringEntity);}}

这里在 Postman 这个工具上进行 Post 操作

以上三个例子都是在电脑端调用的,这和在手机端调用是同个效果的

基本的操作就介绍到这里,再具体的内容可以看示例代码:AndroidServer

欢迎关注我的简书账号:叶应是叶

95人点赞

Android 解析

"哈,希望可以得到一份鼓励,让我喝杯咖啡"

赞赏支持还没有人赞赏,支持一下

叶志陈https://github.com/leavesC

总资产513 (约37.90元)共写了20.0W字获得2,658个赞共1,211个粉丝

已关注

全部评论15只看作者

按时间倒序

按时间正序

昨日d书生

15楼 2019.10.12 09:19

发现同一个局域网下 是可以的 用外网就无法访问呢?

赞 回复

帅气的昵称呢啊吧

14楼 2019.04.16 14:45

楼主你好,我跑了下你的demo,能下载文件和传json数据,但是图片看不到.而且工程一直在报这个java.net.SocketTimeoutException: Read timed out错误,不知道是哪里的问题,请指教

赞 回复

遇见_ca39

13楼 2019.01.04 11:03

看了看楼主的源码,知道文件上专是用fileUpload来实现的,但是里面的FileItemFactory该怎么实现?谢谢

赞 回复

諾言_cfbf

12楼 2018.11.16 11:50

在JsonHandler类中 String content = HttpRequestParser.getContentFromBody(httpRequest); 得到的content 附带这种数据 ----------------------------958044966615931359259061-- 怎么去掉

赞 回复

前年的邂逅_Jerry

11楼 2018.11.08 09:21

为什么mp4文件不能在iOS手机上在线播放?安卓上是可以的.

赞 回复

前年的邂逅_Jerry

2018.11.08 09:21

@GetMapping("/get/video/{isLock}/{fileName}")
public ResponseBody getVideo(@PathVariable(name = "isLock") int isLock, @PathVariable(name = "fileName") String fileName) {
Logger.i(TAG, "getVideo isLock:" + isLock + ", fileName:" + fileName);
String path;
if (isLock == LOCK_VEDIO) {
path = COLLISION_VIDEO_DIR;
} else {
path = FONT_VIDEO_DIR;
}
String filePath = TextUtils.concat(path, fileName).toString();
File file = new File(filePath);
return new FileBody(file);
}

回复

添加新评论

一页书啊

10楼 2018.04.27 23:13

请问用这个库可以实现两个手机的长连接吗,就是客户端手机可以一直从服务端手机接收数据

赞 回复

熊猫仙

9楼 2018.04.27 14:38

准备用xamarin的绑定库引入这个jar包,但是一开始就报错无数,不知道该如何入手,希望自己能坚持搞下去,也希望有同样兴趣的人一起研究。

赞 回复

Cosecant

8楼 2018.04.27 08:28

可能ObjectBox的数据浏览的网页页面就是类似于这种功能

赞 回复

JethroHuang

7楼 2018.04.26 15:05

就是linux deploy

赞 回复

JethroHuang

6楼 2018.04.26 15:04

还是喜欢把Android弄成centos这样的发行版,然后想怎么写怎么写,想用php就用php,想用python就用python,想用JAVA就用java

在 Android 设备上搭建 Web 服务器相关推荐

  1. centos+7虚拟机web服务器,CentOS7上搭建WEB服务器

    mysql 安装 直接yum install mysql-server是不可以的 1 wget http://repo.mysql.com/mysql-community-release-el7-5. ...

  2. mac搭建网站服务器,Mac上搭建Web服务器--Apache

    局域网搭建 Web 服务器测试环境,因为Mac OS X 自带了 Apache 和 PHP 环境,我们只需要简单的启动它就行了. 1.命令:sudo apachectl start Apache服务器 ...

  3. 在自己的电脑上搭建web服务器和FTP在同一局域网如何被其他机器访问

    一.搭建web服务器 1.首先在开始屏幕中打开"搜索",输入"控制面板",并打开; .在控制面板窗口中,找到"程序",点击, 3.在打开的& ...

  4. 在VMware上搭建web服务器

    1.创建角色 开始–>管理工具–>服务器–>服务器管理器–>角色–>右击,选择添加角色–>web服务器II–>安装 2.web服务器网站的配置 开始–> ...

  5. 在Rayeager px2上搭建web服务器anmpp

    2019独角兽企业重金招聘Python工程师标准>>> 1.使用root工具获取root权限. 2.安装anmpp.apk http://www.anmpp.net 3.下载anmp ...

  6. Linux上部署web服务器并发布web项目

    近在学习如何在linux上搭建web服务器来发布web项目,由于本人是linux新手,所以中间入了不少坑,搞了好久才搞出点成果. 以下是具体的详细步骤以及我对此做的一些总结和个人的一些见解,希望对跟我 ...

  7. 安卓Termux搭建web服务器【公网远程手机Android服务器】

    文章目录 概述 1.搭建apache 2.安装cpolar内网穿透 3.公网访问配置 4.固定公网地址 5.添加站点 转载自cpolar极点云的文章:[手机建站]Termux+Cpolar内网穿透,搭 ...

  8. 废旧Android手机搭建个人服务器:ksweb搭建Web服务器+Termux、Ngrok实现内网穿透

    写在前面: 本篇博客介绍利用废旧手机搭建一个服务器,可以放自己的网页搭建网站 之前闲着没事,低价买了个虚拟主机,放了自己的静态网页,搭建了个人博客引导网站,后来虚拟主机被打死,凑巧了解到相关知识,于是 ...

  9. gnuradio android手机,如何搭配USRP在安卓设备上搭建GNU Radio

    原标题:如何搭配USRP在安卓设备上搭建GNU Radio 在这篇文章中,我们会使用安卓设备通过USB连接USRP.所以就需要USRP B2xx(B200, B210, 或者是 B200mini),这 ...

最新文章

  1. shell脚本自动化部署服务
  2. 转载:逻辑思维提升表达
  3. python学习笔记8--socket编程
  4. css中标签显示模式、块元素、行内元素、行内块元素、显示模式转换
  5. echarts formatter_牛X!用 Echarts 打造一个轮播图!
  6. JavaScript如何实现字符串拼接操作
  7. 转数组_Java中IO必杀技-文件转字节数组
  8. 听了那么多语音识别,你知道它的发展史吗?
  9. 重庆大学c语言程序设计基础,c语言程序设计基础黄文胜
  10. 机房搬迁的一般步骤方案
  11. 谈谈架构 -- architect
  12. sql 字段逗号分割
  13. Spring Kafka 之 @KafkaListener 单条或批量处理消息
  14. 【C语言】街区最短路径问题解题思路
  15. RuntimeError: Could not find GCC executable.
  16. 融资租赁系统-覆盖业务全场景数据服务
  17. 已解决:Traceback (most recent call last): File “d:\python3.6\lib\runpy.py“,
  18. 程序员一定会有35岁危机吗?三分天注定,七分靠打拼
  19. 安卓终端神器Termux (后面还有Termux常用的快捷键,妥妥干货分享,记得点赞收藏哦!)
  20. 使用Jest进行React单元测试

热门文章

  1. Python 解决报错NameError: name ‘LEFT‘ is not defined
  2. qt qml 界面程序 适配4K屏幕 简单方法
  3. 一种基于机器学习的电影推荐系统设计
  4. Unity中的宏定义
  5. 数据指标体系搭建实践
  6. 手把手教你美国亚马逊直购
  7. vite项目(vue-ts)搭建常用插件引入方式
  8. Daily Scrum Meeting 11.05
  9. 华为高管又出事了!涉嫌受贿被带走!拿着几百万年薪,为啥还要贪?
  10. 什么是企业数据?企业工商数据如何获取的。