【NanoHTTPD】Android,使用NanoHTTPD搭建服务器,接受Http请求,最佳实践
•
移动开发
Android,NanoHTTPD搭建服务器,接受Http请求最佳实践
1,了解
安卓app,作为服务器,接受Http,get post 请求推送数据,NanoHTTPD是一个免费、轻量级的(只有一个Java文件) HTTP服务器,可以很好地嵌入到Java程序中。支持 GET, POST, PUT, HEAD 和 DELETE 请求,支持文件上传,占用内存很小。
开源地址: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<String, List> 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,开启网络权限,注册服务,后台运行
自定义服务类,继承 Service
public class MyNanoHttpService extends Service {
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 来做服务。
本文来自网络,不代表协通编程立场,如若转载,请注明出处:https://www.net2asp.com/3a574a28d5.html
