当前版本:jdk1.8
1. 声明
当前内容主要为使用Apache Mina实现一个简单的http服务器,并完成默认json数据的响应,当前内容参考:apache mina源码
主要pom依赖
<dependency>
<groupId>org.apache.mina</groupId>
<artifactId>mina-core</artifactId>
<version>2.1.5</version>
</dependency>
<dependency>
<groupId>org.apache.mina</groupId>
<artifactId>mina-http</artifactId>
<version>2.1.5</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.mina/mina-transport-serial -->
<dependency>
<groupId>org.apache.mina</groupId>
<artifactId>mina-transport-serial</artifactId>
<version>2.1.5</version>
</dependency>
2. Demo实现
一个简单的服务器Server
public class HttpServer {
public static void main(String[] args) {
IoAcceptor acceptor = new NioSocketAcceptor();
LoggingFilter loggingFilter = new LoggingFilter();
loggingFilter.setMessageReceivedLogLevel(LogLevel.DEBUG);
acceptor.getFilterChain().addLast("log", loggingFilter);
acceptor.getFilterChain().addLast("httpServerCodec", new HttpServerCodec());
acceptor.setHandler(new HttpServerHandler());
try {
acceptor.bind(new InetSocketAddress("localhost", 8081));
System.out.println("start http server....");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
httpServer对应的处理Handler
import java.nio.ByteBuffer;
import java.nio.charset.CharacterCodingException;
import java.nio.charset.CharsetEncoder;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.service.IoHandlerAdapter;
import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.http.DateUtil;
import org.apache.mina.http.api.DefaultHttpResponse;
import org.apache.mina.http.api.HttpEndOfContent;
import org.apache.mina.http.api.HttpMethod;
import org.apache.mina.http.api.HttpRequest;
import org.apache.mina.http.api.HttpStatus;
import org.apache.mina.http.api.HttpVersion;
public class HttpServerHandler extends IoHandlerAdapter {
private static final CharsetEncoder ENCODER = StandardCharsets.UTF_8.newEncoder();
@Override
public void sessionIdle(IoSession session, IdleStatus status) throws Exception {
// TODO Auto-generated method stub
super.sessionIdle(session, status);
System.out.println("idle ==>" + status);
}
@Override
public void exceptionCaught(IoSession session, Throwable cause) throws Exception {
// TODO Auto-generated method stub
super.exceptionCaught(session, cause);
session.closeNow();
}
List<ByteBuffer> requestBody;
@Override
public void messageSent(IoSession session, Object message) throws Exception {
// TODO Auto-generated method stub
// super.messageSent(session, message);
System.out.println("message sent");
}
@Override
public void messageReceived(IoSession session, Object message) throws Exception {
// TODO Auto-generated method stub
// super.messageReceived(session, message);
// 当前的message就是HttpRequest的实现类
if (message == null) {
return;
}
HttpRequest httpRequest = null;
if (message instanceof HttpRequest) {
httpRequest = (HttpRequest) message;
// 获取请求路径
String requestPath = httpRequest.getRequestPath();
// 获取请求类型
HttpMethod method = httpRequest.getMethod();
// 获取请求参数
String queryString = httpRequest.getQueryString();
/*
* Map<String, String> headers = httpRequest.getHeaders();
* Iterator<Entry<String, String>> iterator = headers.entrySet().iterator();
* while (iterator.hasNext()) { Entry<String, String> next = iterator.next();
* System.out.println(next.getKey() + ":" + next.getValue()); }
*/
System.out.println("url:" + requestPath);
System.out.println("method:" + method);
System.out.println("queryString:" + queryString);
System.out.println("httpRequest");
} else if (message instanceof ByteBuffer) {
// 接受post请求的消息体
requestBody.add((ByteBuffer) message);
System.out.println("byteBuffer");
} else if (message instanceof HttpEndOfContent) {
// we received all the post content, send the crap back
sendResponse(session);
System.out.println("httpEndOfContent");
}
}
// 发送json结果到前台
public void sendResponse(IoSession session) {
System.out.println("send response....");
// 写出默认响应
writeDefaultResponse(session);
String jsonResult = "{\"status\":\"ok\"}";
// 写出body
writeJsonBody(jsonResult, session);
// 写出结束
session.write(new HttpEndOfContent());
session.close(false);
}
private Map<String, String> createHeaders() {
Map<String, String> headers = new HashMap<String, String>();
headers.put("Server", "Apache MINA Server");
headers.put("Date", DateUtil.getCurrentAsString());
headers.put("Connection", "keep-alive");
headers.put("Content-Language", "zh-CN");
headers.put("Content-Type", "application/json; charset=utf-8");
return headers;
}
private void writeDefaultResponse(IoSession session) {
Map<String, String> headers = createHeaders();
DefaultHttpResponse defaultHttpResponse = new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SUCCESS_OK,
headers);
session.write(defaultHttpResponse);
}
private void writeJsonBody(String json, IoSession session) {
IoBuffer buf = IoBuffer.allocate(json.length()).setAutoExpand(true);
try {
buf.putString(json, ENCODER);
buf.flip();
session.write(buf);
} catch (CharacterCodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
这里的HttpServerCodec具有解码和加码类
3. 测试结果
首先启动当前的server:该server默认在8081端口
访问当前的http://localhost:8081/login
得到响应结果如下:
测试成功!
4. 主要易错的地方
这里主要出现的问题是如何响应http客户端的问题(找到Encoder即可解决问题),响应数据是要encoder的,server接受数据是decoder
由于是http请求所以可以定位到HttpServerEncoder
所以实际响应为(这个也对应请求中的部分):
- 首先发送httpResonse主要写出响应状态、http的版本、headers等并写出一个换行
- 如果有ByteBuffer就会写出(对应http响应中的body)
- 最后写出一个HttpEndOfContent表示http的响应内容结束
注意写出的数据必须使用IoBuffer 作为写出的body
(直接使用ByteBuffer好像没有作用
IoBuffer buf = IoBuffer.allocate(json.length()).setAutoExpand(true);
buf.putString(json, ENCODER);
buf.flip();
自此一个完整的http请求响应就完成了