serveur HTTP simple en Java utilisant uniquement l'API Java SE


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 requêtes HTTP et formater manuellement les réponses HTTP? L'API Java SE encapsule bien la fonctionnalité du client HTTP dans HttpURLConnection, mais existe-t-il un analogue pour la fonctionnalité du serveur HTTP?

Juste pour être clair, le problème que j'ai avec beaucoup d'exemples ServerSocket que j'ai vus en ligne est qu'ils font leur propre demande analyse / formatage des réponses et gestion des erreurs, ce qui est fastidieux, sujet aux erreurs et peu susceptible d'être complet, et j'essaie de l'éviter pour ces raisons.

Comme exemple de la manipulation HTTP manuelle que j'essaie d'éviter:

Http://java.sun.com/developer/technicalArticles/Networking/Webserver/WebServercode.html

Author: BalusC, 2010-09-17

17 answers

Depuis Java SE 6, il existe un serveur HTTP intégré dans Sun Oracle JRE. Le com.sun.net.httpserver le résumé du package décrit les classes impliquées et contient des exemples.

Voici un exemple de coup d'envoi copypasted à partir de leurs documents, vous pouvez simplement le copier 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();
        }
    }

}

Noté devrait être que la partie response.length() dans leur exemple est mauvaise, elle aurait dû être response.getBytes().length. Même dans ce cas, la méthode getBytes() doit spécifier explicitement le jeu de caractères que vous spécifiez ensuite dans l'en-tête de réponse. Hélas, bien que mal orienté pour les débutants, ce n'est après tout qu'un exemple de coup d'envoi de base.

Exécutez-le et allez à la http://localhost:8000/test et vous verrez la réponse suivante:

Voici la réponse


Quant à l'utilisation de com.sun.* classes, notez que ce n'est, contrairement à ce que certains développeurs pensent, absolument pas interdit par la FAQ bien connue Pourquoi Les développeurs Ne Devraient Pas Écrire Des Programmes Qui appellent 'sun' Paquets . Cette FAQ concerne le package sun.* (tel que sun.misc.BASE64Encoder) pour une utilisation interne par le JRE Oracle (ce qui tuerait donc votre application lorsque vous l'exécutez sur un JRE différent), pas le package com.sun.*. Sun / Oracle ne fait que développer des logiciels au-dessus de l'API Java SE eux-mêmes, comme toutes les autres entreprises telles qu'Apache, etc. L'utilisation de classes com.sun.* n'est déconseillée (mais pas interdite) que lorsqu'elle concerne une implémentation d'une certaine API Java, telle que GlassFish (Java EE impl), Mojarra (JSF impl), Jersey (JAX-RS impl), etc.

 401
Author: BalusC, 2017-10-19 06:58:46

Découvrez NanoHttpd

"NanoHTTPD est un serveur HTTP léger conçu pour l'intégration dans d'autres applications, publié sous une licence BSD modifiée.

Il est en cours de développement sur Github et utilise Apache Maven pour les builds et les tests unitaires "

 41
Author: letronje, 2017-01-03 16:04:44

La solution com.sun.net.httpserver n'est pas portable à travers JREs. Il est préférable d'utiliser l'API webservices officielle dans javax.xml.ws pour démarrer 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. 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);
    }
}
 25
Author: gruenewa, 2014-07-07 13:30:53

Jetez un oeil au serveur web "Jetty" Jetty . Superbe morceau de logiciel Open Source qui semble répondre à toutes vos exigences.

Si vous insistez pour lancer le vôtre, jetez un œil à la classe "httpMessage".

 19
Author: James Anderson, 2015-07-23 13:11:38

J'aime cette question parce que c'est un domaine où il y a une innovation continue et il y a toujours un besoin d'avoir un serveur léger, surtout quand on parle de serveurs intégrés dans de petits appareils(er). Je pense que les réponses se divisent en deux grands groupes.

  1. Thin-server : contenu statique vers le haut du serveur avec un traitement minimal, un traitement de contexte ou de session.
  2. Small-server : ostensiblement a a de nombreuses qualités de serveur de type httpD avec une empreinte aussi petite que possible loin avec.

Alors que je pourrais considérer les bibliothèques HTTP comme: Jetty, Composants Http Apache, Netty et d'autres pour être plus comme une installation de traitement HTTP brut. L'étiquetage est très subjectif, et dépend du genre de chose que vous avez été appelé à livrer pour les petits sites. Je fais cette distinction dans l'esprit de la question, en particulier la remarque...

  • "...sans écrire de code pour analyser manuellement les requêtes HTTP et formatez manuellement les réponses HTTP..."

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. Un mini-serveur est quelque chose qui peut vous donner des fonctionnalités similaires à un serveur Web complet (comme disons, Tomcat) sans cloches et de sifflets, faible volume, de bonnes performances 99% du temps. Un serveur mince semble plus proche du phrasé original juste un peu plus que raw peut-être avec une fonctionnalité de sous-ensemble limitée, assez pour vous faire bien paraître 90% du temps. Mon idée de raw serait me fait bien paraître 75% - 89% du temps sans conception et codage supplémentaires. Je pense que si/quand vous atteignez le niveau des fichiers de GUERRE, nous avons laissé le" petit " pour les serveurs bonsi qui ressemble à tout ce qu'un grand serveur fait plus petit.

Options de serveur mince

Options du mini-serveur:

  • Étincelle Java ... De bonnes choses sont possibles avec beaucoup de constructions d'aide comme les filtres, les modèles, etc.
  • MadVoc ... vise à être bonsaï et pourrait bien être tel ;-)

Parmi les autres choses à considérer, j'inclurais l'authentification, la validation, l'internationalisation, en utilisant quelque chose comme FreeMaker ou un autre outil de modèle pour rendre la sortie de la page. Sinon gérer HTML l'édition et le paramétrage sont susceptibles de faire ressembler le travail avec HTTP à des noughts-n-cross. Naturellement, tout dépend le degré de souplesse dont vous avez besoin pour être. S'il s'agit d'un fax piloté par menu, cela peut être très simple. Plus il y a d'interactions, plus votre framework doit être " plus épais". Bonne question, bonne chance!

 16
Author: will, 2014-09-04 15:05:18

Il était une fois que je cherchais quelque chose de similaire - un serveur HTTP léger mais entièrement fonctionnel que je pouvais facilement intégrer et personnaliser. J'ai trouvé deux types de solutions potentielles:

  • Des serveurs complets qui ne sont pas si légers ou simples (pour une définition extrême de lightweight.)
  • Des serveurs vraiment légers qui ne sont pas tout à fait des serveurs HTTP, mais des exemples ServerSocket glorifiés qui ne sont même pas compatibles RFC à distance et ne prennent pas en charge les bases couramment nécessaires fonctionnalité.

Donc... J'ai entrepris d'écrire JLHTTP - Le serveur HTTP léger Java.

Vous pouvez l'intégrer dans n'importe quel projet en tant que fichier source unique (si assez long), ou en tant que fichier jar ~50K (~35K dépouillé) sans dépendances. Il s'efforce d'être conforme à la RFC et comprend une documentation étendue et de nombreuses fonctionnalités utiles tout en réduisant au minimum les ballonnements.

Les fonctionnalités incluent: les hôtes virtuels, le service de fichiers à partir du disque, les mappages de type mime via mime standard.types de fichier, génération d'index de répertoire, fichiers de bienvenue, prise en charge de toutes les méthodes HTTP, ETags conditionnels et support d'en-tête If -*, encodage de transfert en morceaux, compression gzip/deflate, HTTPS de base (tel que fourni par la JVM), contenu partiel (continuation du téléchargement), traitement de données multipart/form pour les téléchargements de fichiers, gestionnaires de contexte multiples via API

J'espère que d'autres le trouveront utile: -)

 12
Author: amichair, 2018-06-01 08:43:45

Un serveur web très basique écrit en java peut être trouvé ici http://library.sourcerabbit.com/v/?id=19

 8
Author: Nikos, 2014-01-18 22:47:28

Spark est la plus simple, voici un guide de démarrage rapide: http://sparkjava.com/

 8
Author: Laercio Metzner, 2015-06-22 12:32:46

Il est possible de créer un httpserver qui fournit un support de base pour les servlets J2EE avec juste le JDK et l'api de servlet dans quelques lignes de code.

J'ai trouvé cela très utile pour les servlets de test unitaires, car il démarre beaucoup plus rapidement que les autres conteneurs légers (nous utilisons jetty pour la production).

La plupart des serveurs httpservers très légers ne prennent pas en charge les servlets, mais nous en avons besoin, alors j'ai pensé partager.

L'exemple ci-dessous fournit un servlet de base support, ou jette et UnsupportedOperationException pour les choses non encore implémentées. Il utilise le com. sun. net.httpserver.HttpServer pour le support 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());
    }
}
 7
Author: f.carlsen, 2013-11-28 08:55:50

Je peux fortement recommander de regarder dans Simple, surtout si vous n'avez pas besoin de capacités de servlet mais simplement d'accéder aux objets request/reponse. Si vous avez besoin de REPOS, vous pouvez mettre Jersey sur le dessus, si vous avez besoin de sortie HTML ou similaire, il y a Freemarker. J'aime vraiment ce que vous pouvez faire avec cette combinaison, et il y a relativement peu d'API à apprendre.

 6
Author: Waldheinz, 2010-09-17 18:29:40

Vous pouvez également jeter un œil à un cadre d'application NIO tel que:

  1. Netty: http://jboss.org/netty
  2. Apache Mina: http://mina.apache.org/ ou son sous-projet AsyncWeb: http://mina.apache.org/asyncweb /
 5
Author: ThiamTeck, 2010-09-18 12:04:57

Ce code est meilleur que le nôtre, il vous suffit d'ajouter 2 bibliothèques: javax.servelet.jar et org.mortbay.jetée.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();
    }
}
 5
Author: leandro, 2012-09-21 10:35:00

Caisse Simple. c'est un serveur intégrable assez simple avec un support intégré pour une grande variété d'opérations. J'aime particulièrement son modèle de filetage..

Incroyable!

 3
Author: Olu, 2015-07-15 10:43:57
 3
Author: George, 2015-10-15 14:20:38

Que diriez-vous du projet Apache Commons HttpCore?

Du site web:... Objectifs HttpCore

  • Implémentation des aspects de transport HTTP les plus fondamentaux
  • Équilibre entre de bonnes performances et la clarté et l'expressivité de API
  • Petite empreinte mémoire (prévisible)
  • Bibliothèque autonome (pas de dépendances externes au-delà de JRE)
 2
Author: I. Joseph, 2013-02-11 21:52:42

Vous pouvez écrire un serveur Java assez simple embedded Jetty.

Embedded Jetty signifie que le serveur (Jetty) est livré avec l'application plutôt que de déployer l'application sur un serveur Jetty externe.

Donc, si en approche non intégrée votre webapp intégrée dans un fichier WAR qui s'est déployé sur un serveur externe (Tomcat / Jetty / etc), dans embedded Jetty, vous écrivez la webapp et instanciez le serveur jetty dans la même base de code.

Un exemple pour le serveur Java Embedded Jetty, vous pouvez git clone et utiliser: https://github.com/stas-slu/embedded-jetty-java-server-example

 0
Author: Stas, 2017-06-29 11:14:44

Essayez ceci https://github.com/devashish234073/Java-Socket-Http-Server/blob/master/README.md

Cette api a créé un serveur http à l'aide de sockets. Détail:
1.It obtient la demande du navigateur sous forme de texte
2.L'analyse pour récupérer les informations d'URL , la méthode ,les attributs, etc.
3.Crée une réponse dynamique à l'aide du mappage d'URL défini
4.Envoie la réponse au navigateur.

Par exemple, voici comment le constructeur dans la "Réponse.java " classe convertit une réponse brute dans une réponse http:


réponse du public (Chaîne resp){
Date date = nouvelle date();
String start = " HTTP/1.1 200 OK \ r \ n";
String header = "Date: "+date.toString ()+" \ r \ n";
- tête+= "Content-Type: text/html\r\n";
- tête+= "Content-length: "+resp.longueur ()+" \ r \ n";
- tête+="\r\n";
ceci.resp=début + en-tête + resp;
}

 0
Author: Devashish Priyadarshi, 2018-05-25 19:19:44