最近在IDEA插件开发中遇到了一个场景,就是插件需要接受某个网页的HTTP请求,然后根据该请求做出某些响应。
比如说集成单点登录系统,需要插件在本地浏览器中打开某个页面,然后在网页中进行登录,登录完成后由网页调用插件对外暴露的接口,通知插件已经完成登录。 这个过程中就需要插件具有一个webserver。
一说起webserver,咱们可能首先想到的是tomcat,apache等等,不是说这些不可以完成上述需求,只不过为了这么一个接口嵌入这么多的依赖,有点得不偿失,更何况是插件开发,追求的就是最小依赖产生最大的价值。
经调研有两种实现方法,一种是基于jdk自带的HttpServer类实现,另一种是使用apache.http包的Boostrap实现(推荐)。
JDK的HttpServer实现
这种实现方式最大的优势在于不用引入第三方依赖,实现较为简单。源码如下:
import com.sun.net.httpserver.HttpServer;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.charset.StandardCharsets;
public class HttpServerTest {
public static void main(String[] args) throws IOException {
HttpServer server = HttpServer.create(new InetSocketAddress(8080), 0);
server.createContext("/hello", exchange ->
exchange.getResponseBody().write("hello world".getBytes(StandardCharsets.UTF_8)));
server.start();
// server.stop(0);
// server.start(); 此行会报错
}
}
但是这种实现也有其缺点,目前遇到的最大的问题就是重启问题。查看了源代码中的stop
方法注释:
/**
* stops this server by closing the listening socket and disallowing
* any new exchanges from being processed. The method will then block
* until all current exchange handlers have completed or else when
* approximately <i>delay</i> seconds have elapsed (whichever happens
* sooner). Then, all open TCP connections are closed, the background
* thread created by start() exits, and the method returns.
* Once stopped, a HttpServer cannot be re-used. <p>
*
* @param delay the maximum time in seconds to wait until exchanges have finished.
* @throws IllegalArgumentException if delay is less than zero.
*/
public abstract void stop (int delay);
重点就是:Once stop, a HttpServer cannot be re-used. 。
也就是说用这种方式开启HTTP服务是不能随用随启的,只能一直开启,因此这种在插件开发中有安全隐患。
使用apache.http的Bootstrap实现
这种实现方法需要使用到第三方依赖,不过在IDEA插件开发过程中不需要在意这个,因为官方的SDK中就集成了apache的工具包,包含了http模块。源代码如下:
import org.apache.http.entity.BasicHttpEntity;
import org.apache.http.impl.bootstrap.HttpServer;
import org.apache.http.impl.bootstrap.ServerBootstrap;
import java.io.ByteArrayInputStream;
import java.io.IOException;
public class ApacheHttpServerTest {
public static void main(String[] args) throws IOException {
ServerBootstrap bootstrap = ServerBootstrap.bootstrap();
bootstrap.setListenerPort(8080);
bootstrap.registerHandler("/hello", (httpRequest, httpResponse, httpContext) -> {
BasicHttpEntity entity = new BasicHttpEntity();
entity.setContent(new ByteArrayInputStream("hello world".getBytes()));
httpResponse.setEntity(entity);
});
HttpServer httpServer = bootstrap.create();
httpServer.start();
httpServer.stop();
httpServer.start();
}
}
这种实现也比较简单,而且与servlet的写法像。最重要的是支持“重启”,也就意味着可以随用随启,不用的时候关闭,也不会有什么安全隐患了。
在IDEA插件开发中,使用apache-http的实现更加合理,既不用额外引入依赖,又可以做到随用随启,比较适合这种场景,推荐!!!
2 Comments