Android,NanoHTTPD搭建服務器,接受Http請求最佳實踐
1,了解
安卓app,作為服務器,接受Http,get post 請求推送數(shù)據(jù),NanoHTTPD是一個免費、輕量級的(只有一個Java文件) HTTP服務器,可以很好地嵌入到Java程序中。支持 GET, POST, PUT, HEAD 和 DELETE 請求,支持文件上傳,占用內(nèi)存很小。
開源地址:GitHub - NanoHttpd/nanohttpd: Tiny, easily embeddable HTTP server in Java.
2,引入依賴
implementation 'org.nanohttpd:nanohttpd:2.3.1'
3,開始集成
這里需要注意以下三點問題:
- 系統(tǒng)端口:0~1023,用于運行標準服務,例如 HTTP 服務(端口 80)、FTP 服務(端口 21)等。
注冊端口:1024~49151,用于運行注冊的應用程序或服務,例如 DNS 服務(端口 53)、SMTP 服務(端口 25)等。
動態(tài)/私有端口:49152~65535,可以被動態(tài)分配給任何應用程序或服務,通常用于客戶端。 所以,如下代碼,我們聲明監(jiān)聽的端口是49152
,避免端口被占用- 請求攜帶中文,需要將請求頭設置
UTF-8
字符集,防止中文亂碼,如下代碼27
行進行相關(guān)處理;- 客戶端發(fā)送
POST
請求,獲取POST
,Body
參數(shù),需要session.parseBody(new HashMap<String,String>())
,如下代碼40行
處理,獲取Body
參數(shù)。
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 解決客戶端請求參數(shù)攜帶中文,出現(xiàn)中文亂碼問題
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()) {
//獲取請求頭數(shù)據(jù)
Map<String,String> header = session.getHeaders();
//獲取傳參參數(shù)
Map<String, String> params = new HashMap<String, String>();
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<String,Object> result = new HashMap<>();
//TODO 寫你的業(yè)務邏輯.....
//響應客戶端
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<String>> 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
,開啟網(wǎng)絡權(quán)限,注冊服務,后臺運行
<!--開啟網(wǎng)絡權(quán)限-->
<uses-permission android:name="android.permission.INTERNET" />
<application>
<!--注冊服務>
<service android:name=".nanoHttpd.MyNanoHttpService" />
</application>
自定義服務類,繼承 Service
文章來源:http://www.zghlxwxcb.cn/news/detail-494900.html
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
啟動服務文章來源地址http://www.zghlxwxcb.cn/news/detail-494900.html
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//實例化 獲取ip 地址
MyNanoHttpdServer.getInstance(getIPAddress());
//啟動服務監(jiān)聽
startService(new Intent(this, MyNanoHttpService.class));
}
/**
* 獲得IP地址,分為兩種情況:
* 一:是wifi下;
* 二:是移動網(wǎng)絡下;
*/
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網(wǎng)絡
try {
//Enumeration<NetworkInterface> en=NetworkInterface.getNetworkInterfaces();
for (Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements(); ) {
NetworkInterface intf = en.nextElement();
for (Enumeration<InetAddress> 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) {//當前使用無線網(wǎng)絡
WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
WifiInfo wifiInfo = wifiManager.getConnectionInfo();
//調(diào)用方法將int轉(zhuǎn)換為地址字符串
String ipAddress = intIP2StringIP(wifiInfo.getIpAddress());//得到IPV4地址
return ipAddress;
}
} else {
//當前無網(wǎng)絡連接,請在設置中打開網(wǎng)絡
}
return null;
}
/**
* 將得到的int類型的IP轉(zhuǎn)換為String類型
* @param ip
* @return
*/
public static String intIP2StringIP(int ip) {
return (ip & 0xFF) + "." +
((ip >> 8) & 0xFF) + "." +
((ip >> 16) & 0xFF) + "." +
(ip >> 24 & 0xFF);
}
}
4,總結(jié)
- 如果想要APP保持服務持久可用,又不被系統(tǒng)限制網(wǎng)絡,,可以進入系統(tǒng)設置中設置“電池不優(yōu)化”。
- 根據(jù)之前的并發(fā)請求測試發(fā)現(xiàn),只會返回同一條數(shù)據(jù),而不是分別響應每一個接口請求。
目前尚未找到適合的處理方式,暫且只能控制請求端的請求頻次。 - 如果并發(fā)請求大,請不要使用NanoHTTPD,還是通過JAVA和Spring 來做服務。
到了這里,關(guān)于【NanoHTTPD】Android,使用NanoHTTPD搭建服務器,接受Http請求,最佳實踐的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!