Existe-t-il un moyen de créer un serveur HTTP très basique (ne prenant en charge que GET/POST) en Java en utilisant uniquement l'API Java SE, sans écrire de code pour analyser manuellement les demandes HTTP et formater manuellement les réponses HTTP? L'API Java SE encapsule bien la fonctionnalité client HTTP dans HttpURLConnection, mais existe-t-il une fonctionnalité analogique pour serveur HTTP?
Pour être clair, le problème que j'ai avec beaucoup d'exemples ServerSocket que j'ai vus en ligne est qu'ils effectuent leur propre analyse syntaxique de requête/formatage de réponse et le traitement des erreurs, ce qui est fastidieux, sujet aux erreurs et peu susceptible d'être complet et j'essaie de l'éviter pour ces raisons.
Voici un exemple de la manipulation HTTP manuelle que j'essaie d'éviter:
http://Java.Sun.com/developer/technicalArticles/Networking/Webserver/WebServercode.html
Depuis Java SE 6, il existe un serveur HTTP intégré à Soleil Oracle JRE. Le résumé du package com.Sun.net.httpserver
présente les classes impliquées et contient des exemples.
Voici un exemple de lancement copypasted de leur documentation (à tous ceux qui essaient de l'éditer néanmoins, parce que c'est un morceau de code laid, veuillez ne pas le faire, c'est un copier-coller, pas le mien, de plus, vous ne devriez jamais éditer des citations. sauf s’ils ont changé dans la source originale). Vous pouvez simplement le copier-coller sur 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(); } } }
Il convient de noter que la partie response.length()
de leur exemple est mauvaise, elle aurait dû être response.getBytes().length
. Même dans ce cas, la méthode getBytes()
doit explicitement spécifier le jeu de caractères que vous indiquez ensuite dans l'en-tête de la réponse. Hélas, même s’il est trompeur, ce n’est qu’un exemple de base.
Exécutez-le et accédez à http: // localhost: 8000/test et vous verrez la réponse suivante:
C'est la réponse
En ce qui concerne l'utilisation des classes com.Sun.*
, notez que ceci est, contrairement à ce que pensent certains développeurs, absolument pas interdit par le bien connu FAQ Pourquoi les développeurs ne doivent-ils pas écrire des programmes qui appellent les packages "Sun" . Ce FAQ concerne le package Sun.*
(tel que Sun.misc.BASE64Encoder
) pour une utilisation interne par le JRE Oracle (qui tuerait donc votre application lorsque vous l'exécutez sur un autre JRE), pas le package com.Sun.*
. Sun/Oracle vient également de développer des logiciels au-dessus de l'API Java SE, comme toutes les autres entreprises telles qu'Apache, etc. L'utilisation de classes com.Sun.*
n'est déconseillée (mais pas interdite) lorsqu'il s'agit d'une implementation d'une certaine API Java, telle que GlassFish (implémentation Java EE), Mojarra (impl. JSF), Jersey (impl. JAX-RS), etc. .
Départ NanoHttpd
"NanoHTTPD est un serveur HTTP léger conçu pour s’intégrer dans d’autres applications, publié sous une licence BSD modifiée.
Il est en cours de développement chez Github et utilise Apache Maven pour les versions et les tests unitaires "
La solution com.Sun.net.httpserver n'est pas portable entre JRE. Il est préférable d’utiliser l’API officielle des services Web dans javax.xml.ws pour amorcer un serveur HTTP minimal.
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)
EDIT: cela fonctionne réellement! Le code ci-dessus ressemble à Groovy ou quelque chose comme ça. Voici une traduction en Java que j'ai testée:
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);
}
}
Consultez le serveur Web "Jetty" Jetty . Superbe logiciel Open Source qui semble répondre à tous vos besoins.
Si vous insistez pour lancer le vôtre, jetez un coup d’œil à la classe "httpMessage".
J'aime cette question, car il s'agit d'un domaine dans lequel l'innovation est permanente et où il est toujours nécessaire de disposer d'un serveur léger, en particulier lorsqu'il est question de serveurs intégrés dans de plus petits appareils. Je pense que les réponses se divisent en deux grands groupes.
Bien que je puisse envisager des bibliothèques HTTP telles que: Jetty , Apache Http Components , Netty et d’autres ressemblent davantage à des installations de traitement HTTP brutes. L'étiquetage est très subjectif et dépend du type de document que vous avez été invité à fournir pour les petits sites. Je fais cette distinction dans l'esprit de la question, en particulier la remarque à propos de ...
Ces outils bruts vous permettent de le faire (comme décrit dans d'autres réponses). Ils ne se prêtent pas vraiment à un style prêt à l'emploi consistant à créer un serveur léger, intégré ou mini-serveur. Un mini-serveur est quelque chose qui peut vous donner des fonctionnalités similaires à celles d'un serveur Web à fonctions complètes (comme, par exemple, Tomcat ), sans fioritures, un faible volume et de bonnes performances 99% du temps. Un serveur léger semble plus proche de la formulation originale qu'un peu plus brut que peut-être avec une fonctionnalité de sous-ensemble limitée, assez pour vous rendre beau 90% du temps. Mon idée de raw me ferait bien paraître entre 75% et 89% du temps sans conception ni codage supplémentaire. Je pense que si/lorsque vous atteignez le niveau des fichiers WAR, nous avons laissé le "petit" pour les serveurs Bonsi qui ressemble à tout ce qu'un gros serveur fait plus petit.
Options de serveur mince
Options du mini-serveur:
Parmi les autres éléments à prendre en compte, je voudrais inclure l’authentification, la validation, l’internationalisation, en utilisant quelque chose comme FreeMaker ou un autre outil de modèle pour afficher la sortie de la page. Sinon, la gestion de l’édition et du paramétrage HTML risque de faire en sorte que le travail avec HTTP ressemble à rien à rien. Naturellement, tout dépend de la souplesse dont vous avez besoin. Si c'est un télécopieur piloté par menu, cela peut être très simple. Plus il y a d'interactions, plus le 'épais} _' doit être votre framework. Bonne question, bonne chance!
Il était une fois, je recherchais quelque chose de similaire: un serveur HTTP léger mais fonctionnel, que je pouvais facilement intégrer et personnaliser. J'ai trouvé deux types de solutions potentielles:
Alors ... je me suis mis à écrire JLHTTP - Le serveur HTTP Java Lightweight .
Vous pouvez l'intégrer à n'importe quel projet en tant que fichier source unique (même s'il est assez long) ou en tant que fichier jar ~ 50K (~ 35K supprimé) sans dépendance. Il s’efforce d’être conforme aux RFC et comprend une documentation détaillée et de nombreuses fonctionnalités utiles, tout en minimisant les problèmes.
Les fonctions incluent: hôtes virtuels, serveurs de fichiers à partir du disque, mappages de types mime via un fichier standard mime.types, génération d'index de répertoires, fichiers de bienvenue, prise en charge de toutes les méthodes HTTP, prise en charge des en-têtes ETags conditionnelles et If- *, codage de transfert par blocs, gzip/deflate compression, HTTPS de base (fourni par la machine virtuelle Java), contenu partiel (poursuite du téléchargement), traitement multipart/form-data pour les téléchargements de fichiers, gestionnaires de contexte multiples via API ou annotations, analyse de paramètres (chaîne de requête ou x-www-form-urlencoded corps), etc.
J'espère que d'autres le trouveront utile :-)
Spark est le plus simple, voici un guide de démarrage rapide: http://sparkjava.com/
Un très serveur Web de base écrit en Java peut être trouvé ici http://library.sourcerabbit.com/v/?id=19
Il est possible de créer un serveur https qui fournit un support de base pour les servlets J2EE avec seulement le JDK et l’API de servlet dans quelques lignes de code.
J'ai trouvé cela très utile pour les servlets de test unitaire, car il démarre beaucoup plus rapidement que les autres conteneurs légers (nous utilisons une jetée pour la production).
La plupart des serveurs https très légers ne fournissent pas de support pour les servlets, mais nous en avons besoin, alors j'ai pensé partager.
L'exemple ci-dessous fournit une prise en charge de base des servlets ou des levées et UnsupportedOperationException pour des éléments non encore implémentés. Il utilise com.Sun.net.httpserver.HttpServer pour la prise en charge http de base.
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());
}
}
Je peux fortement recommander de regarder dans Simple , en particulier si vous n'avez pas besoin des fonctionnalités de Servlet, mais simplement d'un accès aux objets requête/réponse. Si vous avez besoin de REST, vous pouvez y ajouter Jersey. Si vous avez besoin de générer du code HTML ou similaire, utilisez Freemarker. J'aime vraiment ce que vous pouvez faire avec cette combinaison, et il y a relativement peu d'API à apprendre.
Ce code est meilleur que le nôtre, il suffit d’ajouter 2 bibliothèques: javax.servlet.jar et org.mortbay.jetty.jar .
Jetée de classe:
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);
}
}
}
Classe de servlet:
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();
}
}
Vous pouvez également consulter certains cadres d’application NIO tels que:
Départ takes
. Regardez https://github.com/yegor256/takes pour des informations rapides
caisse Simple . c’est un serveur simple et intégrable avec un support intégré pour toute une variété d’opérations. J'aime particulièrement son modèle de filetage ..
Incroyable!
Qu'en est-il d'Apache Commons HttpCore project?
Sur le site Web: ... Objectifs HttpCore
Vous pouvez écrire un Jetty intégré serveur Java très simple.
Embedded Jetty signifie que le serveur (Jetty) est fourni avec l'application, contrairement au déploiement de l'application sur un serveur Jetty externe.
Donc, si dans une approche non intégrée, votre application Web intégrée dans un fichier WAR déployé sur un serveur externe ( Tomcat /Jetty/etc), dans Jetty intégrée, vous écrivez l'application Web et instanciez le serveur Jetée dans le même code. base.
Un exemple de serveur Jetty Java intégré vous pouvez git clone et utiliser: https://github.com/stas-slu/embedded-jetty-Java-server-example
Toutes les réponses ci-dessus décrivent en détail le gestionnaire de requêtes à thread unique principal.
réglage:
server.setExecutor(Java.util.concurrent.Executors.newCachedThreadPool());
Autorise le traitement de plusieurs demandes via plusieurs threads à l'aide du service exécuteur.
Donc, le code de fin sera quelque chose comme ci-dessous:
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();
}
}
}
Essayez ceci https://github.com/devashish234073/Java-Socket-Http-Server/blob/master/README.md
Cette API a crée un serveur http utilisant des sockets. Détails:
1.Il reçoit la demande du navigateur sous forme de texte
2. Il permet de récupérer les informations d'URL, la méthode, les attributs, etc. .
3.Crée une réponse dynamique en utilisant le mappage d’URL défini
4.Envoie la réponse au navigateur.
Par exemple, voici comment le constructeur de la classe "Response.Java" convertit une réponse brute en une réponse http:
public Response (String resp) {
Date date = new Date ();
String start = "HTTP/1.1 200 OK\r\n";
En-tête de chaîne = "Date:" + date.toString () + "\ r\n";
header + = "Content-Type: text/html\r\n";
header + = "Content-length:" + resp.length () + "\ r\n";
en-tête + = "\ r\n";
this.resp = start + header + resp;
}