MockNet -- Android網絡接口開發與測試神器
最近寫了一個輕量級的服務器框架 MockNet,可以在 Android 上或者 Java 平臺快速搭建服務器,方便開發和測試網絡接口,不需要服務器知識就可以使用。
寫這個框架的原因
平時寫項目的時候,總會遇到這些情況
- 服務器接口還沒有寫好,Android 客戶端只能先做一些界面的開發工作,遇到需要展示數據的地方只能先留著或者用一些假數據填充,服務器接口寫好以后,這些代碼又得刪掉或者再改。
- 在調試網絡接口的時候,往往需要后臺客戶端一起配合,有時候會花不少時間確認是服務器還是客戶端的問題,之后聯調也很花時間。
- 在沒有網絡但是又需要展示應用功能的時候,只能用一堆 if else 來添加假數據或者數據庫里的數據。代碼寫起來很不方便。
寫這個框架就是想解決這些問題。
- 首先是網絡接口開發的問題,通過 MockNet 這個庫,無需后臺接口完成就可以進行網絡接口的開發,開發流程要更順暢一點。
- 其次是網絡接口調試的問題,通過 MockNet 這個庫,在沒有后臺同學的幫助下也可以對 Android 客戶端網絡接口進行調試。
- 最后是沒有網絡需要展示功能的問題,通過 MockNet 這個庫,沒有網絡一樣可以展示應用的網絡功能。
框架介紹
MockNet 是為了方便客戶端網絡接口的開發和測試而寫的,簡單來說就是在本地啟動服務器用來響應客戶端的網絡請求。但是不需要有服務器開發知識,幾行代碼就可以添加此功能。
代碼上傳到了 github 上,網址: https://github.com/5A59/MockNet
庫下載
Gradle
// 在模塊的 gradle 文件中添加下面的代碼
compile 'com.zy.mocknet:mocknet:1.0'
Maven
<dependency>
<groupId>com.zy.mocknet</groupId>
<artifactId>mocknet</artifactId>
<version>1.0</version>
<type>pom</type>
</dependency>
jar包下載
框架使用
MockNet 使用簡單,步驟如下:
- 修改網絡訪問 ip 為本地 ip (127.0.0.1:port 或 本地真實ip:port),因為服務器是在本地搭建的。
- 初始化。
// 創建 MockNet MockNet mockNet = MockNet.create();
- 添加對請求的處理
MockNet 中對每一個 request 都會對應一個 response,request 和 response 和起來稱為一個 MockConnection,添加對請求的處理就是添加 MockConnection 實例。MockConnection conn = MockConnectionFactory.getInstance() .createGeneralConnection("/*", "general connection"); mockNet.addConnection(conn);
- 啟動服務
// 默認使用 8088 端口 mockNet.start(); // 使用指定的端口 mockNet.start(int port);
- 關閉服務
mockNet.stop();
以上就是 MockNet 的使用方法。還可以通過鏈式調用來寫,代碼更簡潔。
MockNet mockNet = MockNet.create()
.addConnection(MockConnectionFactory.getInstance()
.createGeneralConnection("/test", "{'res':'ok'}"))
.addConnection(MockConnectionFactory.getInstance()
.createGeneralConnection("/*", "{'res':'ok'}"))
.start();
進階使用
上面是 MockNet 的簡單使用,還有更多的擴展用法。
-
自定義 MockConnection
通過 MockConnection.Builder 生成 Builder,并通過 Builder 相關方法構建 MockConnection。Builder 常用的方法可以參看文檔: Builder
-
隨機對請求做出響應
MockNet 內部通過 url 和 method(GET,POST等)來對請求做出區分,在 addConnection 時如果添加了多個相同的 url 和 method 的 MockConnection,會通過 IConnectionSelector 來選擇其中之一進行返回,默認使用 RandomSelector 隨機返回。
可以通過 實現 IConnectionSelector 接口并通過 MockNet.setSelector() 設置返回規則。
-
Log 設置
默認對每個 MockConnection 都會輸出 Log 以幫助調試,如果想關閉 Log,可以在構建 MockConnection 時設置 isLog(false)。
MockNet 的 Log 輸出是由 Logger 和 Printer 完成的,默認設置了 AndroidPrinter 和 JavaPrinter,如果想自定義 Log,可以實現 Printer 接口,并調用 Logger.init(yourPrinter) 設置,但是要在調用了 MockConnection.create() 之后,否則設置會被覆蓋為默認設置
-
自定義 Handler 對請求響應進行處理
MockNet 中對 Request 和 Response 的處理采用了責任鏈模式(可查看后面的框架介紹),通過添加 Handler 增加處理環節,框架自帶的 Handler 有 BlockHandler,LogHandler,VerifyHeaderHandler,VerifyParamHandler,ConnectionHandler。
如果想增加自己的處理環節,請實現 Handler 接口,并通過 MockNet.addHandler(Handler h) 來設置。具體實現方法可參照框架默認實現的 Handler 代碼。
-
支持 https
支持 https 可以通過下面代碼來開啟:
MockNet mockNet = MockNet.create(); mockNet.start(ServerSocketFactory.createHttpsServerSocket(int port, String jksPath, String storePwd));
-
動態處理數據
為了簡化使用方法和加快開發速度,默認只支持了返回靜態數據,暫時沒有對數據進行動態處理。如果想動態處理請求數據,可以繼承 RequestExecutor 接口并實現 execute 方法。在 execute 方法中對請求進行動態處理,并創建 Reponse 返回。
之后通過 Server 構造函數構造 Server 對象并傳入實現 RequestExecutor 接口的類對象。
具體可以參考 MockRequestExecutor 的實現以及 Server 構造函數。
框架架構
上面介紹了框架的使用,這里對框架的實現做一些介紹。
先上一張架構圖。
mocknet.png
自己認為整個架構還是不錯的(-_-)。
整體可分為兩層, Server 層和 Application 層。
Server 層
Server 層主要做的工作是 socket 通信和對 Request,Response 的解析。
Server 類主要是對端口的監聽,接受 socket 請求并創建 RequestRunnable 處理請求。
RequestRunnable 創建后會加入到線程池中。RequestRunnable 類中對請求進行解析,并把請求發送到 RequestExecutor 去處理,RequestExecutor 會返回 Response,RequestRunnable 再負責把 Response 寫入到 socket 中。
Application 層
Application 層工作是對 Request 的處理。通過實現 RequestExecutor 接口處理 Request 并返回 Response。
框架中默認實現 RequestRunnable 接口的是 MockRequestExecutor 類,用來返回靜態消息,如果想動態處理請求,需要自己實現 RequestExecutor 接口,框架后續看情況也可能會增加動態處理請求的功能。
MockRequestExecutor 中主要采用責任鏈模式處理請求,每一個 Handler 都是一個處理環節。這個鏈式的實現是之前看過 OkHttp 代碼學到的。這里貼代碼來看一下。
HandlerChain chain = new RealHandlerChain();
public Response execute(Request request) {
for (Handler h : userHandlers) {
chain.addHandler(h);
}
if (initHandler) {
chain.addHandler(new BlockHandler());
chain.addHandler(new VerifyParamHandler());
chain.addHandler(new VerifyHeaderHandler());
chain.addHandler(new LogHandler());
chain.addHandler(new ConnectionHandler());
}
return chain.start(request);
}
上面是 MockRequestExecutor 的 execute() 函數的實現,首先將 Handler 加入到 chain 中,之后調用 chain.start() 開始調用 Handler 進行處理。
再看一下 HandlerChain 的 start() 方法實現。
public Response start(Request request) {
Handler handler = handlers.get(index);
Response response = handler.handle(request, this, index);
return response;
}
直接調用了 handler.handle()進行處理,在 Handler 的 handle 方法中需要調用下一個 Handler。
框架默認實現了幾個 Handler:BlockHandler,VerifyParamHandler,VeriffyHeaderHandler,LogHandler,ConnectionHandler。
這些通過名字可以看出功能,這里重點看一下 ConnectionHandler。
ConnectionHandler 是處理鏈調用的終點,負責生成 Response。
ConnectionHandler 的 handle 方法如下:
String method = request.getMethod();
String url = request.getRequestUri();
MockConnection connection =
ConnectionStore.getInstance().getConnection(method, url);
if (connection == null) {
return Response.create404Response();
}
Response response = new Response();
// 省略對 Response 的設置
return response;
通過請求的 url 和 method 從 ConnectionStore 中獲取到 MockConnection,之后用 MockConnection 中的響應信息創建并填充 Response。
那 ConnectionStore 中的 MockConnection 是什么時候放進去的呢?就是在我們開始通過 MockNet.addConnection() 添加的。
這樣整個框架就差不多講完了,具體的細節就請查看 代碼 吧。感覺整個框架實現不難,模塊化和擴展性都還不錯(自夸一下)。
其他
如果有什么問題或者想法可以上 github 提 issue,或者可以郵箱交流 zy5a59@outlook.com。