版權聲明:本文為部落客原創文章,遵循 CC 4.0 BY-SA 版權協定,轉載請附上原文出處連結和本聲明。
本文連結:https://blog.csdn.net/10km/article/details/102568909
NanoHTTPD是一個輕量級的HTTP伺服器,可以很友善地嵌入到Java程式中。是以在android平台上有廣泛的使用。
NanoHTTPD預設是不支援通路跨域(CORS)請求的。如果希望自己的NanoHTTPD服務支援CORS,就要自己實作對CORS請求的響應。
關于什麼是CORS,這個文檔有非常詳細、清晰、全面的闡述:
《HTTP通路控制(CORS)》,如果還不太清楚CORS機制的童鞋,建議先看這篇 文章補補課。
實作對跨域通路的支援的關鍵就是要響應跨請求,跨域請求的METHOD為OPTIONS,對收到的HTTP請求要先識别是否為跨域請求,如果是就發送正确的響應。下面是nanohttpd響應CORS請求的基本邏輯
@Override
public Response serve(IHTTPSession session) {
// 判斷是否為跨域預請求
if(isPreflightRequest(session)){
// 如果是則發送CORS響應告訴浏覽HTTP服務支援的METHOD及HEADERS和請求源
return responseCORS(session);
}
// 業務邏輯
.....
/////
return wrapResponse(session,responseAck(ack));
}
複制
下面是上述代碼中調用的子方法的實作,
注意:因為nanohttp的headers中所有的key都是全小寫,是以你會發現下面的代碼,從headers擷取header時,header的名字都是小寫的。
/**
* 判斷是否為CORS 預檢請求請求(Preflight)
* @param session
* @return
*/
private static boolean isPreflightRequest(IHTTPSession session) {
Map<String, String> headers = session.getHeaders();
return Method.OPTIONS.equals(session.getMethod())
&& headers.containsKey("origin")
&& headers.containsKey("access-control-request-method")
&& headers.containsKey("access-control-request-headers");
}
/**
* 向響應包中添加CORS標頭資料
* @param session
* @return
*/
private Response responseCORS(IHTTPSession session) {
Response resp = wrapResponse(session,newFixedLengthResponse(""));
Map<String, String> headers = session.getHeaders();
resp.addHeader("Access-Control-Allow-Methods","POST,GET,OPTIONS");
String requestHeaders = headers.get("access-control-request-headers");
String allowHeaders = MoreObjects.firstNonNull(requestHeaders, "Content-Type");
resp.addHeader("Access-Control-Allow-Headers", allowHeaders);
//resp.addHeader("Access-Control-Max-Age", "86400");
resp.addHeader("Access-Control-Max-Age", "0");
return resp;
}
/**
* 封裝響應包
* @param session http請求
* @param resp 響應包
* @return resp
*/
private Response wrapResponse(IHTTPSession session,Response resp) {
if(null != resp){
Map<String, String> headers = session.getHeaders();
resp.addHeader("Access-Control-Allow-Credentials", "true");
// 如果請求頭中包含'Origin',則響應頭中'Access-Control-Allow-Origin'使用此值否則為'*'
// nanohttd将所有請求頭的名稱強制轉為了小寫
String origin = MoreObjects.firstNonNull(headers.get("origin", "*");
resp.addHeader("Access-Control-Allow-Origin", origin);
String requestHeaders = headers.get("access-control-request-headers");
if(requestHeaders != null){
resp.addHeader("Access-Control-Allow-Headers", requestHeaders);
}
}
return resp;
}
複制
完整的代碼參見碼雲倉庫代碼:
gu.dtalk.engine.DtalkHttpServer.java