【NanoHTTPD】Android,使用NanoHTTPD搭建服务器,接受Http请求,最佳实践

2024-04-14 1509阅读

Android,NanoHTTPD搭建服务器,接受Http请求最佳实践

1,了解

安卓app,作为服务器,接受Http,get post 请求推送数据,NanoHTTPD是一个免费、轻量级的(只有一个Java文件) HTTP服务器,可以很好地嵌入到Java程序中。支持 GET, POST, PUT, HEAD 和 DELETE 请求,支持文件上传,占用内存很小。

【NanoHTTPD】Android,使用NanoHTTPD搭建服务器,接受Http请求,最佳实践
(图片来源网络,侵删)

开源地址:GitHub - NanoHttpd/nanohttpd: Tiny, easily embeddable HTTP server in Java.

2,引入依赖

implementation 'org.nanohttpd:nanohttpd:2.3.1'

3,开始集成

这里需要注意以下三点问题:

  • 系统端口:0~1023,用于运行标准服务,例如 HTTP 服务(端口 80)、FTP 服务(端口 21)等。

    注册端口:1024~49151,用于运行注册的应用程序或服务,例如 DNS 服务(端口 53)、SMTP 服务(端口 25)等。

    动态/私有端口:49152~65535,可以被动态分配给任何应用程序或服务,通常用于客户端。 所以,如下代码,我们声明监听的端口是 49152 ,避免端口被占用

  • 请求携带中文,需要将请求头设置 UTF-8 字符集,防止中文乱码,如下代码27行进行相关处理;
  • 客户端发送POST请求,获取 POST,Body参数,需要 session.parseBody(new HashMap()),如下代码40行处理,获取Body参数。

    3.1 自定义类,继承 NanoHTTPD

    public class MyNanoHttpdServer extends NanoHTTPD  {
    	
        //声明服务端 端口
        private static final Integer HTTP_PORT = 49152;
        public MyNanoHttpdServer(String hostname, int port) {
            super(hostname, port);
        }
        private volatile static MyNanoHttpdServer myNanoHttpdServer;
     	//TODO	单例模式,获取实例对象,并传入当前机器IP
        public static MyNanoHttpdServer getInstance(String ipAddress) {
            if (myNanoHttpdServer == null) {
                synchronized (MyNanoHttpdServer.class) {
                    if (myNanoHttpdServer == null) {
                        myNanoHttpdServer = new MyNanoHttpdServer(ipAddress, HTTP_PORT);
                    }
                }
            }
            return myNanoHttpdServer;
        }
        @Override
        public Response serve(IHTTPSession session) {
            //TODO  解决客户端请求参数携带中文,出现中文乱码问题
            ContentType ct = new ContentType(session.getHeaders().get("content-type")).tryUTF8();
            session.getHeaders().put("content-type", ct.getContentTypeHeader());
            return dealWith(session);
        }
        private Response dealWith(IHTTPSession  session) {
            Date dateTime = new Date();
            if (Method.POST == session.getMethod()) {
                //获取请求头数据
                Map header = session.getHeaders();
                //获取传参参数
                Map params = new HashMap();
                try {
                    session.parseBody(params);
                    String paramStr = params.get("postData");
                    if(StringUtils.isEmpty(paramStr)){
                        return newFixedLengthResponse("success");
                    }
                    paramStr = paramStr.replace("\r\n"," ");
                    JSONObject jsonParam = JSON.parseObject(paramStr);
                    Map result = new HashMap();
    				//TODO 写你的业务逻辑.....
                    
                     //响应客户端
                     return   newFixedLengthResponse("success");
                } catch (IOException e) {
                    e.printStackTrace();
                } catch (ResponseException e) {
                    e.printStackTrace();
                }
                return   newFixedLengthResponse("success");
            }else if (Method.GET == session.getMethod()){
                Map parameters = session.getParameters();
                return   newFixedLengthResponse("success");
            }
            return newFixedLengthResponse("404");
        }
        public static Response newFixedLengthResponse(String msg) {
            return newFixedLengthResponse(Response.Status.OK, NanoHTTPD.MIME_HTML, msg);
        }
    }
    

    3.2 在 AndroidMainifest.xml,开启网络权限,注册服务,后台运行

    
    
         
        private MyNanoHttpdServer httpServer = MyNanoHttpdServer.getInstance(null);
        @Nullable
        @Override
        public IBinder onBind(Intent intent) {
            return null;
        }
        @Override
        public void onCreate() {
            super.onCreate();
            try {
                httpServer.start();
            } catch (Exception e) {
                e.printStackTrace();
                startService(new Intent(this,MyNanoHttpService.class));
            }
        }
        @Override
        public int onStartCommand(Intent intent, int flags, int startId){
            return super.onStartCommand(intent, flags, startId);
        }
        public void onDestroy() {
            httpServer.stop();
        }
    }
    

    在MainActivity 启动服务

    public class MainActivity extends AppCompatActivity {
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    		 //实例化 获取ip 地址
             MyNanoHttpdServer.getInstance(getIPAddress());
            //启动服务监听
            startService(new Intent(this, MyNanoHttpService.class));
        }
         /**
         * 获得IP地址,分为两种情况:
         * 一:是wifi下;
         * 二:是移动网络下;
         */
        public  String getIPAddress() {
            Context context = WelcomeActivity.this;
            NetworkInfo info = ((ConnectivityManager) context
                    .getSystemService(Context.CONNECTIVITY_SERVICE)).getActiveNetworkInfo();
            if (info != null && info.isConnected()) {
                if (info.getType() == ConnectivityManager.TYPE_MOBILE) {//当前使用2G/3G/4G网络
                    try {
                        //Enumeration en=NetworkInterface.getNetworkInterfaces();
                        for (Enumeration en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements(); ) {
                            NetworkInterface intf = en.nextElement();
                            for (Enumeration enumIpAddr = intf.getInetAddresses(); enumIpAddr.hasMoreElements(); ) {
                                InetAddress inetAddress = enumIpAddr.nextElement();
                                if (!inetAddress.isLoopbackAddress() && inetAddress instanceof Inet4Address) {
                                    return inetAddress.getHostAddress();
                                }
                            }
                        }
                    } catch (SocketException e) {
                        e.printStackTrace();
                    }
                } else if (info.getType() == ConnectivityManager.TYPE_WIFI) {//当前使用无线网络
                    WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
                    WifiInfo wifiInfo = wifiManager.getConnectionInfo();
                    //调用方法将int转换为地址字符串
                    String ipAddress = intIP2StringIP(wifiInfo.getIpAddress());//得到IPV4地址
                    return ipAddress;
                }
            } else {
                //当前无网络连接,请在设置中打开网络
            }
            return null;
        }
        /**
         * 将得到的int类型的IP转换为String类型
         * @param ip
         * @return
         */
        public static String intIP2StringIP(int ip) {
            return (ip & 0xFF) + "." +
                    ((ip >> 8) & 0xFF) + "." +
                    ((ip >> 16) & 0xFF) + "." +
                    (ip >> 24 & 0xFF);
        }
    }
    

    4,总结

    • 如果想要APP保持服务持久可用,又不被系统限制网络,,可以进入系统设置中设置“电池不优化”。
    • 根据之前的并发请求测试发现,只会返回同一条数据,而不是分别响应每一个接口请求。

      目前尚未找到适合的处理方式,暂且只能控制请求端的请求频次。

    • 如果并发请求大,请不要使用NanoHTTPD,还是通过JAVA和Spring 来做服务。
VPS购买请点击我

免责声明:我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理! 图片声明:本站部分配图来自人工智能系统AI生成,觅知网授权图片,PxHere摄影无版权图库和百度,360,搜狗等多加搜索引擎自动关键词搜索配图,如有侵权的图片,请第一时间联系我们,邮箱:ciyunidc@ciyunshuju.com。本站只作为美观性配图使用,无任何非法侵犯第三方意图,一切解释权归图片著作权方,本站不承担任何责任。如有恶意碰瓷者,必当奉陪到底严惩不贷!

目录[+]