手動でHTTP要求を解析して手動でHTTP応答をフォーマットするコードを書かずに、Java SE APIだけを使用して、非常に基本的なHTTPサーバー(GET/POSTのみをサポート)をJavaで作成する方法はありますか? Java SE APIはHttpURLConnectionのHTTPクライアント機能をうまくカプセル化していますが、HTTPサーバー機能の類似物はありますか?
明確にするために、私がオンラインで見た多くのServerSocketの例で私が抱えている問題は、それらが彼ら自身のリクエスト解析/レスポンスフォーマットとエラー処理をするということです。そして私はそれらの理由でそれを避けようとしています。
私が避けようとしている手動のHTTP操作の例として:
http://Java.Sun.com/developer/technicalArticles/Networking/Webserver/WebServercode.html
Java SE 6以降、組み込みのHTTPサーバーがあります 太陽 Oracle JRE。 com.Sun.net.httpserver
package summary は、関係するクラスの概要を示し、例を含みます。
これは、ドキュメントからのコピー例copypastedです(ただし、編集しようとするすべての人に、これはいコードなので、これはしないでください)コピーペーストは私のものではなく、さらに、元のソースで変更されていない限り、引用を編集しないでください)。 Java 6+で実行するだけでコピー&ペーストできます。
package com.stackoverflow.q3732109; import Java.io.IOException; import Java.io.OutputStream; import Java.net.InetSocketAddress; import com.Sun.net.httpserver.HttpExchange; import com.Sun.net.httpserver.HttpHandler; import com.Sun.net.httpserver.HttpServer; public class Test { public static void main(String[] args) throws Exception { HttpServer server = HttpServer.create(new InetSocketAddress(8000), 0); server.createContext("/test", new MyHandler()); server.setExecutor(null); // creates a default executor server.start(); } static class MyHandler implements HttpHandler { @Override public void handle(HttpExchange t) throws IOException { String response = "This is the response"; t.sendResponseHeaders(200, response.length()); OutputStream os = t.getResponseBody(); os.write(response.getBytes()); os.close(); } } }
例のresponse.length()
部分が悪いことに注意してください。response.getBytes().length
である必要があります。それでも、getBytes()
メソッドは、応答ヘッダーで指定する文字セットを明示的に指定する必要があります。悲しいかな、初心者に誤解を与えているとはいえ、結局のところ、これは単なる基本的なキックオフの例です。
実行して http:// localhost:8000/test に移動すると、次の応答が表示されます。
これは応答です
com.Sun.*
クラスの使用に関しては、これは、一部の開発者が考えることとは反対に、よく知られているFAQ によって絶対に禁止されていないことに注意してください「Sun」パッケージを呼び出すプログラム 。そのFAQは、Oracle JREによる内部使用のためのSun.*
パッケージ(Sun.misc.BASE64Encoder
など)に関係します(したがって、異なるJREで実行するとアプリケーションが強制終了されます) com.Sun.*
パッケージ。また、Sun/Oracleは、Apacheなどの他のすべての会社と同様に、Java SE API上でソフトウェアを開発するだけです。 com.Sun.*
クラスの使用は、特定のJava APIの実装に関係する場合にのみ推奨されます(ただし禁止されません)。 GlassFish(Java EE impl)、Mojarra(JSF impl)、Jersey(JAX-RS impl)など。
チェックアウト NanoHttpd
「NanoHTTPDは、Modified BSDライセンスの下でリリースされた、他のアプリケーションへの組み込み用に設計された軽量のHTTPサーバーです。
それはGithubで開発されていて、ビルドと単体テストのためにApache Mavenを使います」
com.Sun.net.httpserver ソリューションはJRE間で移植性がありません。最小のHTTPサーバーをブートストラップするには、 javax.xml.ws の公式WebサービスAPIを使用する方が良いでしょう。
import Java.io._
import javax.xml.ws._
import javax.xml.ws.http._
import javax.xml.transform._
import javax.xml.transform.stream._
@WebServiceProvider
@ServiceMode(value=Service.Mode.PAYLOAD)
class P extends Provider[Source] {
def invoke(source: Source) = new StreamSource( new StringReader("<p>Hello There!</p>"));
}
val address = "http://127.0.0.1:8080/"
Endpoint.create(HTTPBinding.HTTP_BINDING, new P()).publish(address)
println("Service running at "+address)
println("Type [CTRL]+[C] to quit!")
Thread.sleep(Long.MaxValue)
編集:これは実際に動作します!上記のコードはGroovyか何かのように見えます。これが私がテストしたJavaへの翻訳です。
import Java.io.*;
import javax.xml.ws.*;
import javax.xml.ws.http.*;
import javax.xml.transform.*;
import javax.xml.transform.stream.*;
@WebServiceProvider
@ServiceMode(value = Service.Mode.PAYLOAD)
public class Server implements Provider<Source> {
public Source invoke(Source request) {
return new StreamSource(new StringReader("<p>Hello There!</p>"));
}
public static void main(String[] args) throws InterruptedException {
String address = "http://127.0.0.1:8080/";
Endpoint.create(HTTPBinding.HTTP_BINDING, new Server()).publish(address);
System.out.println("Service running at " + address);
System.out.println("Type [CTRL]+[C] to quit!");
Thread.sleep(Long.MAX_VALUE);
}
}
"Jetty" Webサーバー Jetty を見てください。あなたのすべての要求を満たすように思われるオープンソースソフトウェアのすばらしい作品。
あなたが自分自身を転がすことを主張するならば、それから "httpMessage"クラスを見てください。
私はこの質問が好きです。なぜならこれは絶え間ない技術革新があり、特に小型(er)デバイスの組み込みサーバーについて話すときは常に軽量サーバーを持つ必要がある分野です。答えは2つの大きなグループに分けられると思います。
Jetty 、 Apache Httpコンポーネント 、 Netty などのHTTPライブラリを、生のHTTP処理機能のようなものと考えることもできます。ラベリングは非常に主観的なもので、小規模サイト用に提供するためにあなたが要求してきたものの種類によって異なります。私は質問の精神、特に...についての発言でこの区別をしています。
これらの生のツールはあなたにそれをさせます(他の答えで説明されるように)。彼らは、軽量、組み込み、またはミニサーバーを作るという既成のスタイルには向いていません。ミニサーバーとは、フル機能のWebサーバー( Tomcat など)に似たような機能を、鐘を鳴らすことなく、小音量で、99%のパフォーマンスで実現できるものです。シンサーバーは元のフレーズに近いと思われますが、おそらくサブセット機能が限られていることで、生のものよりほんの少しだけ上手くいきます。私の生の考えは、余分なデザインやコーディングをしなくても、75% - 89%見栄えがよくなることです。あなたがWARファイルのレベルに到達したとき、私たちは大きなサーバーがすべて小さくなるようなbonsiサーバー用の「小さい」を残しましたか。
シンサーバーオプション
ミニサーバーオプション:
考慮すべき他のものの中には、認証、検証、国際化、 FreeMaker またはその他のテンプレートツールを使用したページ出力のレンダリングなどがあります。そうでなければ、HTMLの編集とパラメータ化を管理することで、HTTPを扱うのが難しくなります。当然、それはすべてあなたがどれだけ柔軟になる必要があるかに依存します。それがメニュー方式のファクシミリ装置であるならば、それは非常に簡単でありえる。相互作用が多いほど、フレームワークは '厚い' 'である必要があります。良い質問、頑張ってください!
かつて私は似たようなものを探していました - 私は簡単に埋め込んでカスタマイズすることができた軽量だが十分に機能的なHTTPサーバーです。私は2つのタイプの潜在的な解決策を見つけました:
それで... JLHTTP - JavaライトウェイトHTTPサーバーを書くことにしました 。
単一の(かなり長い場合)ソースファイルとして、または依存関係のない〜50K jar(〜35K削除)として、任意のプロジェクトに埋め込むことができます。これは、RFCに準拠することを目指しており、膨大な量を最小限に抑えながら、豊富なドキュメントと多くの便利な機能を含んでいます。
機能は次のとおりです。仮想ホスト、ディスクからのファイル配信、標準mime.typesファイルによるMIMEタイプマッピング、ディレクトリインデックス生成、ウェルカムファイル、すべてのHTTPメソッドのサポート、条件付きETagおよびIf- *ヘッダーサポート、チャンク転送エンコード、gzip/deflate圧縮、基本HTTPS(JVM提供)、部分コンテンツ(ダウンロード継続)、ファイルアップロード用のマルチパート/フォームデータ処理、APIまたはアノテーションを介したマルチコンテキストハンドラ、パラメータ解析(クエリ文字列またはx-www-form-urlencoded)体)など.
私は他の人がそれを役に立つと思ってくれることを願っています:-)
スパークは最も簡単です、ここにクイックスタートガイドがあります。 http://sparkjava.com/ /
わずか数行のコードで、JDKとサーブレットAPIだけでJ2EEサーブレットの基本的なサポートを提供するhttpserverを作成することが可能です。
他の軽量コンテナよりもはるかに速く起動するので、私はこれを単体テストサーブレットに非常に役立つと思いました(プロダクションにはJettyを使用します)。
ほとんどの非常に軽量のhttpserverはサーブレットのサポートを提供していませんが、それらが必要なので、私は共有すると思いました。
以下の例は、基本的なサーブレットのサポートを提供するか、まだ実装されていないものについてはUnsupportedOperationExceptionをスローします。それは基本的なhttpサポートのためにcom.Sun.net.httpserver.HttpServerを使います。
import Java.io.*;
import Java.lang.reflect.*;
import Java.net.InetSocketAddress;
import Java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;
import com.Sun.net.httpserver.HttpExchange;
import com.Sun.net.httpserver.HttpHandler;
import com.Sun.net.httpserver.HttpServer;
@SuppressWarnings("deprecation")
public class VerySimpleServletHttpServer {
HttpServer server;
private String contextPath;
private HttpHandler httpHandler;
public VerySimpleServletHttpServer(String contextPath, HttpServlet servlet) {
this.contextPath = contextPath;
httpHandler = new HttpHandlerWithServletSupport(servlet);
}
public void start(int port) throws IOException {
InetSocketAddress inetSocketAddress = new InetSocketAddress(port);
server = HttpServer.create(inetSocketAddress, 0);
server.createContext(contextPath, httpHandler);
server.setExecutor(null);
server.start();
}
public void stop(int secondsDelay) {
server.stop(secondsDelay);
}
public int getServerPort() {
return server.getAddress().getPort();
}
}
final class HttpHandlerWithServletSupport implements HttpHandler {
private HttpServlet servlet;
private final class RequestWrapper extends HttpServletRequestWrapper {
private final HttpExchange ex;
private final Map<String, String[]> postData;
private final ServletInputStream is;
private final Map<String, Object> attributes = new HashMap<>();
private RequestWrapper(HttpServletRequest request, HttpExchange ex, Map<String, String[]> postData, ServletInputStream is) {
super(request);
this.ex = ex;
this.postData = postData;
this.is = is;
}
@Override
public String getHeader(String name) {
return ex.getRequestHeaders().getFirst(name);
}
@Override
public Enumeration<String> getHeaders(String name) {
return new Vector<String>(ex.getRequestHeaders().get(name)).elements();
}
@Override
public Enumeration<String> getHeaderNames() {
return new Vector<String>(ex.getRequestHeaders().keySet()).elements();
}
@Override
public Object getAttribute(String name) {
return attributes.get(name);
}
@Override
public void setAttribute(String name, Object o) {
this.attributes.put(name, o);
}
@Override
public Enumeration<String> getAttributeNames() {
return new Vector<String>(attributes.keySet()).elements();
}
@Override
public String getMethod() {
return ex.getRequestMethod();
}
@Override
public ServletInputStream getInputStream() throws IOException {
return is;
}
@Override
public BufferedReader getReader() throws IOException {
return new BufferedReader(new InputStreamReader(getInputStream()));
}
@Override
public String getPathInfo() {
return ex.getRequestURI().getPath();
}
@Override
public String getParameter(String name) {
String[] arr = postData.get(name);
return arr != null ? (arr.length > 1 ? Arrays.toString(arr) : arr[0]) : null;
}
@Override
public Map<String, String[]> getParameterMap() {
return postData;
}
@Override
public Enumeration<String> getParameterNames() {
return new Vector<String>(postData.keySet()).elements();
}
}
private final class ResponseWrapper extends HttpServletResponseWrapper {
final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
final ServletOutputStream servletOutputStream = new ServletOutputStream() {
@Override
public void write(int b) throws IOException {
outputStream.write(b);
}
};
private final HttpExchange ex;
private final PrintWriter printWriter;
private int status = HttpServletResponse.SC_OK;
private ResponseWrapper(HttpServletResponse response, HttpExchange ex) {
super(response);
this.ex = ex;
printWriter = new PrintWriter(servletOutputStream);
}
@Override
public void setContentType(String type) {
ex.getResponseHeaders().add("Content-Type", type);
}
@Override
public void setHeader(String name, String value) {
ex.getResponseHeaders().add(name, value);
}
@Override
public javax.servlet.ServletOutputStream getOutputStream() throws IOException {
return servletOutputStream;
}
@Override
public void setContentLength(int len) {
ex.getResponseHeaders().add("Content-Length", len + "");
}
@Override
public void setStatus(int status) {
this.status = status;
}
@Override
public void sendError(int sc, String msg) throws IOException {
this.status = sc;
if (msg != null) {
printWriter.write(msg);
}
}
@Override
public void sendError(int sc) throws IOException {
sendError(sc, null);
}
@Override
public PrintWriter getWriter() throws IOException {
return printWriter;
}
public void complete() throws IOException {
try {
printWriter.flush();
ex.sendResponseHeaders(status, outputStream.size());
if (outputStream.size() > 0) {
ex.getResponseBody().write(outputStream.toByteArray());
}
ex.getResponseBody().flush();
} catch (Exception e) {
e.printStackTrace();
} finally {
ex.close();
}
}
}
public HttpHandlerWithServletSupport(HttpServlet servlet) {
this.servlet = servlet;
}
@SuppressWarnings("deprecation")
@Override
public void handle(final HttpExchange ex) throws IOException {
byte[] inBytes = getBytes(ex.getRequestBody());
ex.getRequestBody().close();
final ByteArrayInputStream newInput = new ByteArrayInputStream(inBytes);
final ServletInputStream is = new ServletInputStream() {
@Override
public int read() throws IOException {
return newInput.read();
}
};
Map<String, String[]> parsePostData = new HashMap<>();
try {
parsePostData.putAll(HttpUtils.parseQueryString(ex.getRequestURI().getQuery()));
// check if any postdata to parse
parsePostData.putAll(HttpUtils.parsePostData(inBytes.length, is));
} catch (IllegalArgumentException e) {
// no postData - just reset inputstream
newInput.reset();
}
final Map<String, String[]> postData = parsePostData;
RequestWrapper req = new RequestWrapper(createUnimplementAdapter(HttpServletRequest.class), ex, postData, is);
ResponseWrapper resp = new ResponseWrapper(createUnimplementAdapter(HttpServletResponse.class), ex);
try {
servlet.service(req, resp);
resp.complete();
} catch (ServletException e) {
throw new IOException(e);
}
}
private static byte[] getBytes(InputStream in) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
while (true) {
int r = in.read(buffer);
if (r == -1)
break;
out.write(buffer, 0, r);
}
return out.toByteArray();
}
@SuppressWarnings("unchecked")
private static <T> T createUnimplementAdapter(Class<T> httpServletApi) {
class UnimplementedHandler implements InvocationHandler {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
throw new UnsupportedOperationException("Not implemented: " + method + ", args=" + Arrays.toString(args));
}
}
return (T) Proxy.newProxyInstance(UnimplementedHandler.class.getClassLoader(),
new Class<?>[] { httpServletApi },
new UnimplementedHandler());
}
}
特にサーブレット機能を必要とせず、単に要求/応答オブジェクトにアクセスする必要がある場合は、 Simple を調べることを強くお勧めします。あなたがRESTを必要とするなら、あなたはそれの上にJerseyを置くことができます、あなたがHTMLまたは同様のものを出力する必要があるならばFreemarkerがあります。私はあなたがこの組み合わせでできることが本当に大好きです、そして学ぶべきAPIは比較的少ないです。
このコードは私たちのものより優れています、あなたは2つのlibsを追加する必要があるだけです: javax.servelet.jar と org.mortbay.jetty.jar 。
クラス桟橋:
package jetty;
import Java.util.logging.Level;
import Java.util.logging.Logger;
import org.mortbay.http.SocketListener;
import org.mortbay.jetty.Server;
import org.mortbay.jetty.servlet.ServletHttpContext;
public class Jetty {
public static void main(String[] args) {
try {
Server server = new Server();
SocketListener listener = new SocketListener();
System.out.println("Max Thread :" + listener.getMaxThreads() + " Min Thread :" + listener.getMinThreads());
listener.setHost("localhost");
listener.setPort(8070);
listener.setMinThreads(5);
listener.setMaxThreads(250);
server.addListener(listener);
ServletHttpContext context = (ServletHttpContext) server.getContext("/");
context.addServlet("/MO", "jetty.HelloWorldServlet");
server.start();
server.join();
/*//We will create our server running at http://localhost:8070
Server server = new Server();
server.addListener(":8070");
//We will deploy our servlet to the server at the path '/'
//it will be available at http://localhost:8070
ServletHttpContext context = (ServletHttpContext) server.getContext("/");
context.addServlet("/MO", "jetty.HelloWorldServlet");
server.start();
*/
} catch (Exception ex) {
Logger.getLogger(Jetty.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
サーブレットクラス
package jetty;
import Java.io.IOException;
import Java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class HelloWorldServlet extends HttpServlet
{
@Override
protected void doGet(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws ServletException, IOException
{
String appid = httpServletRequest.getParameter("appid");
String conta = httpServletRequest.getParameter("conta");
System.out.println("Appid : "+appid);
System.out.println("Conta : "+conta);
httpServletResponse.setContentType("text/plain");
PrintWriter out = httpServletResponse.getWriter();
out.println("Hello World!");
out.close();
}
}
また、次のようなNIOアプリケーションフレームワークを見ることもできます。
takes
を調べてください。 https://github.com/yegor256/takes を見てください。
チェックアウト シンプル 。かなりシンプルな組み込み可能なサーバーで、さまざまな操作をサポートしています。私は特にそのスレッドモデルが大好きです。
すごい!
上記のすべての回答が、シングルメインスレッドリクエストハンドラに関する詳細です。
設定:
server.setExecutor(Java.util.concurrent.Executors.newCachedThreadPool());
Executorサービスを使用して複数のスレッドを介して複数の要求を処理することを許可します。
そのため、終了コードは以下のようになります。
import Java.io.IOException;
import Java.io.OutputStream;
import Java.net.InetSocketAddress;
import com.Sun.net.httpserver.HttpExchange;
import com.Sun.net.httpserver.HttpHandler;
import com.Sun.net.httpserver.HttpServer;
public class App {
public static void main(String[] args) throws Exception {
HttpServer server = HttpServer.create(new InetSocketAddress(8000), 0);
server.createContext("/test", new MyHandler());
//Thread control is given to executor service.
server.setExecutor(Java.util.concurrent.Executors.newCachedThreadPool());
server.start();
}
static class MyHandler implements HttpHandler {
@Override
public void handle(HttpExchange t) throws IOException {
String response = "This is the response";
long threadId = Thread.currentThread().getId();
System.out.println("I am thread " + threadId );
response = response + "Thread Id = "+threadId;
t.sendResponseHeaders(200, response.length());
OutputStream os = t.getResponseBody();
os.write(response.getBytes());
os.close();
}
}
}
Apache Commons HttpCore projectはどうですか。
Webサイトから:... HttpCore Goals
あなたはかなり単純な 埋め込まれたJetty Javaサーバーを書くことができます。
Embedded Jettyとは、外部Jettyサーバーにアプリケーションをデプロイするのではなく、サーバー(Jetty)がアプリケーションと一緒に出荷されることを意味します。
つまり、埋め込みでないアプローチでWebアプリケーションが外部サーバー( Tomcat / Jetty/etc)にデプロイされたWARファイルに組み込まれている場合は、埋め込みJettyでWebアプリケーションを作成し、同じコードベースでjettyサーバーをインスタンス化します。
組み込みJetty Javaサーバーの例では、 git clone を使用できます。 https://github.com/stas-slu/embedded-jetty-Java-server-example
これを試してみてください https://github.com/devashish234073/Java-Socket-Http-Server/blob/master/README.md
このAPIはソケットを使用してHTTPサーバーを作成しました。
たとえば、Response.Java
クラスのコンストラクタが生の応答をhttp応答に変換する方法は次のとおりです。
public Response(String resp){
Date date = new Date();
String start = "HTTP/1.1 200 OK\r\n";
String header = "Date: "+date.toString()+"\r\n";
header+= "Content-Type: text/html\r\n";
header+= "Content-length: "+resp.length()+"\r\n";
header+="\r\n";
this.resp=start+header+resp;
}