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