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

333

Existe-t-il un moyen de créer un serveur HTTP très basique (prenant uniquement en charge 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é 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 formatage de requête / réponse et traitement des erreurs, ce qui est fastidieux, sujet aux erreurs et peu susceptible d'être exhaustif, et j'essaye 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

demandeur
la source
3
Umm ... la réponse courte est non. Si vous voulez quelque chose qui gère les publications et les requêtes sans écrire manuellement les en-têtes http, vous pouvez utiliser des servlets. Mais c'est java ee. Si vous ne voulez pas utiliser quelque chose comme ça, les sockets et l'analyse manuelle sont la seule autre option que je connaisse.
Matt Phillips
3
Je sais que ce n'est pas dans l'esprit de SO, mais je vous exhorte à reconsidérer votre dégoût pour les API Java EE. Comme certaines des réponses l'ont mentionné, il existe des implémentations très simples telles que Jetty qui vous permettent d'incorporer un serveur Web dans votre application autonome tout en profitant de l'API de servlet. Si vous ne pouvez absolument pas utiliser l'API Java EE pour une raison quelconque, veuillez ignorer mon commentaire :-)
Chris Thompson
1
Les "servlets" ne sont pas vraiment des "Java EE". Ils ne sont qu'un moyen d'écrire des plugins qui peuvent être appelés par l'application environnante en réponse à l'activité des messages (de nos jours, généralement des requêtes HTTP). Fournir un environnement d'hébergement de servlet "en utilisant uniquement l'API Java SE" est exactement ce que font Jetty et Tomcat. Bien sûr, vous voudrez peut-être éliminer la complexité indésirable, mais vous devrez peut-être alors décider d'un sous-ensemble des attributs et configurations autorisés de GET / POST. Souvent, cela n'en vaut pas la peine, sauf pour des problèmes de sécurité / embarqués spéciaux.
David Tonhofer
1
Il pourrait être utile de parcourir cette liste de serveurs http avant de prendre une décision. java-source.net/open-source/web-servers
ThreaT

Réponses:

469

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

Voici un exemple de lancement copypasté à partir de leurs documents (pour toutes les personnes qui essaient de le modifier néanmoins, car 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 modifier les citations à moins qu'elles aient changé dans la source d'origine). Vous pouvez simplement le copier / coller / exécuter 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 response.length()partie de leur exemple est mauvaise, elle aurait dû l'être response.getBytes().length. Même dans ce cas, la getBytes()méthode doit spécifier explicitement le jeu de caractères que vous spécifiez ensuite dans l'en-tête de réponse. Hélas, quoique peu judicieux pour les débutants, ce n'est après tout qu'un exemple de base du coup d'envoi.

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

Telle est la réponse


En ce qui concerne l'utilisation des com.sun.*classes, notez que cela, contrairement à ce que certains développeurs pensent, n'est absolument pas interdit par la FAQ bien connue Pourquoi les développeurs ne devraient pas écrire de programmes qui appellent des packages 'sun' . Cette FAQ concerne le sun.*package (tel que sun.misc.BASE64Encoder) à usage interne par Oracle JRE (qui tuerait ainsi votre application lorsque vous l'exécutez sur un autre JRE), pas le com.sun.*package. Sun / Oracle vient également de développer des logiciels en plus de l'API Java SE eux-mêmes comme toutes les autres sociétés telles qu'Apache, etc. L'utilisation de com.sun.*classes n'est déconseillée (mais pas interdite) lorsqu'elle concerne une implémentation d'une certaine API Java, comme GlassFish (implément Java EE), Mojarra (impl JSF), Jersey (impl JAX-RS), etc.

BalusC
la source
19
@Waldheinz: comme en @Software vous confondez sun.*avec com.sun.*. Par exemple, voyez-vous de la documentation sur l' sun.*API? Regardez ici: java.sun.com/products/jdk/faq/faq-sun-packages.html Cela dit -il quelque chose com.sun.*? Le com.sun.*est juste utilisé pour leur propre logiciel public qui ne fait pas partie de l'API Java. Ils développent également des logiciels en plus de l'API Java, comme toutes les autres sociétés.
BalusC
4
je pense que c'est un serveur http très agréable à utiliser dans les cas de test d'intégration. merci pour l'astuce!
Andreas Petersson
13
Si vous utilisez Eclipse et obtenez une erreur du type "Restriction d'accès: le type HttpExchange n'est pas accessible en raison d'une restriction sur la bibliothèque requise ...", stackoverflow.com/a/10642163 indique comment désactiver cette vérification d'accès.
Samuli Pahaoja
13
FWIW ceci est également présent dans OpenJDK.
Jason C
6
Les classes mentionnées ici sont balisées @jdk.Exporteddans le code source d'OpenJDK, ce qui signifie que l'API est considérée comme publique et sera disponible sur Java 9 (certains autres com.sun.*packages deviendront indisponibles en raison de Project Jigsaw).
Jules
42

Découvrez NanoHttpd

"NanoHTTPD est un serveur HTTP léger conçu pour être intégré 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 builds et les tests unitaires "

letronje
la source
4
Une mise en garde: il est probable que NanoHTTPD n'ait pas de protection contre les attaques par les arbres - vous devriez vérifier si il sera diffusé sur une adresse publique. J'entends par là les attaques où une demande similaire GET /../../blahblah http/1.1est émise et le serveur passe au-dessus de la racine du site Web et dans le fichier système, servant des fichiers qui peuvent être utilisés pour compromettre ou attaquer à distance le système, comme un fichier de mot de passe.
Lawrence Dol
7
Cela semble être corrigé. La version actuelle génère un 403 if (uri.startsWith ("..") || uri.endsWith ("..") || uri.indexOf ("../")> = 0).
Lena Schimmel
5
Je ne comprends pas comment c'est une réponse à cette question.
kimathie
28

La solution com.sun.net.httpserver n'est pas portable entre les JRE. Il vaut mieux utiliser l'API webservices officielle 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. 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);
    }
}
gruenewa
la source
1
+1 pour être portable. Dommage que vous ne puissiez pas définir le type de contenu de la réponse tel quel text/xml.
icza
1
Je pense que vous pouvez faire la classe <code> Server implémente le fournisseur <DataSource> {</code> ... puis spécifier le Content-Type dans la méthode <code> getContentType () </code> de DataSource. En outre, vous pouvez également injecter WebServiceContext: <code> @Resource WebServiceContext ctx; </code> pour définir d'autres en-têtes et lire les paramètres de demande. Malheureusement, la définition du type de contenu via WebServiceContext ne fonctionne pas.
gruenewa
4
Pourriez-vous expliquer pourquoi com.sun.net.HttpServer n'est pas portable entre JRE s'il vous plaît?
javabeangrinder
3
Non, je ne pense pas. Cela ne fonctionnera pas sur l'implémentation Java d'IBM et peut-être aussi sur d'autres. Et même si cela fonctionne maintenant, les API internes sont autorisées à changer. Pourquoi ne pas simplement utiliser l'API officielle?
gruenewa
1
Ce lien: docs.oracle.com/javase/9/docs/api/java.xml.ws-summary.html dit que le module java.xml.ws est déconseillé depuis Java 9.
Erel Segal-Halevi
23

J'aime cette question car 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 embarqués dans des petits (er) appareils. Je pense que les réponses se répartissent en deux grands groupes.

  1. Thin-server : contenu statique sur serveur avec un minimum de traitement, de contexte ou de session.
  2. Petit serveur : ostensiblement, a de nombreuses qualités de serveur de type httpD avec une empreinte aussi petite que possible.

Bien que je puisse considérer les bibliothèques HTTP comme: Jetty , Apache Http Components , Netty et d'autres comme des installations de traitement HTTP brutes. L'étiquetage est très subjectif et dépend du genre de choses que vous avez été invité à livrer pour les petits sites. Je fais cette distinction dans l'esprit de la question, en particulier la remarque sur ...

  • "... sans écrire de code pour analyser manuellement les requêtes HTTP et formater 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 pour créer un mini-serveur léger, intégré ou. Un mini-serveur est quelque chose qui peut vous offrir des fonctionnalités similaires à un serveur Web complet (comme, par exemple, Tomcat ) sans cloches et sifflets, faible volume, bonnes performances 99% du temps. Un serveur léger semble plus proche du phrasé d'origine un peu plus que brut, 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 me ferait bien paraître 75% - 89% du temps sans conception et codage supplémentaires. Je pense que si / quand 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 léger

Options de mini-serveur:

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

Entre 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, la gestion de l'édition et du paramétrage HTML est susceptible de faire ressembler le travail avec HTTP à des noughts-n-crosses. Naturellement, tout dépend de la flexibilité dont vous avez besoin. S'il s'agit d'un télécopieur piloté par menu, cela peut être très simple. Plus il y a d'interactions, plus votre framework doit être « épais ». Bonne question, bonne chance!

volonté
la source
21

Jetez un oeil sur le serveur Web « jetée » jetée . Superbe logiciel Open Source qui semblerait répondre à toutes vos exigences.

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

James Anderson
la source
Je pense que jetty api dépend du servlet.
irréputable du
4
@Irreputable: Non, Jetty est un serveur Web hautement modulaire, qui a un conteneur de servlet comme l'un de ses modules optionnels.
Lawrence Dol
"est là un analogue pour la fonctionnalité du serveur" - oui c'est l'API "servlet". Le conteneur de servlet appelle votre classe après avoir analysé les en-têtes, les cookies, etc.
James Anderson
1
Juste pour mémoire - Jetty est livré avec sa propre implémentation de l'API Servlet et fonctionne très bien avec Java SE
James Anderson
4
Jetty est trop grande et a trop de courbe d'apprentissage avant que l'utilisation réelle de la production ne devienne une possibilité.
ThreaT
18

Il était une fois 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:

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

Alors ... je me suis mis à écrire JLHTTP - Le serveur HTTP léger Java .

Vous pouvez l'intégrer dans n'importe quel projet en tant que fichier source unique (s'il est plutôt long) ou en tant que fichier ~ 50K (~ 35K supprimé) sans dépendances. Il s'efforce d'être conforme à la RFC et comprend une documentation complète et de nombreuses fonctionnalités utiles tout en minimisant les ballonnements.

Les fonctionnalités incluent: hôtes virtuels, service de fichiers à partir du disque, mappages de types MIME via le fichier mime.types standard, génération d'index de répertoire, fichiers de bienvenue, prise en charge de toutes les méthodes HTTP, ETags conditionnels et prise en charge des en-têtes If- *, codage de transfert par blocs, gzip / dégonflage compression, HTTPS de base (tel que fourni par la JVM), contenu partiel (continuation du téléchargement), gestion des données en plusieurs parties / formulaire pour les téléchargements de fichiers, plusieurs gestionnaires de contexte via API ou annotations, analyse des paramètres (chaîne de requête ou x-www-form-urlencoded corps), etc.

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

amichair
la source
La méthode principale est un bon exemple d'utilisation de base, et la FAQ va dans de nombreux détails. Si vous avez des suggestions pour améliorer les documents existants, n'hésitez pas à me contacter directement!
amichair
10

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

Laercio Metzner
la source
8

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 du servlet en quelques lignes de code.

J'ai trouvé cela très utile pour tester des servlets, car il démarre beaucoup plus rapidement que d'autres conteneurs légers (nous utilisons la jetée pour la production).

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

L'exemple ci-dessous fournit une prise en charge de base de servlet, ou jette et UnsupportedOperationException pour des éléments non encore implémentés. Il utilise 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());
    }
}
f.carlsen
la source
Il manque certaines méthodes sur ServletOutputStream et ServletInputStream
HomeIsWhereThePcIs
version plus récente de l'api servlet, ci-dessus pour 3.0 et ci-dessous. Ajoutez simplement les méthdos manquants au besoin dans l'exemple
f.carlsen
6

Je peux fortement recommander d'étudier Simple , surtout si vous n'avez pas besoin des fonctionnalités de Servlet, mais accédez simplement aux objets request / reponse. Si vous avez besoin de REST, vous pouvez mettre Jersey dessus, si vous avez besoin de sortir du 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.

Waldheinz
la source
+1. J'aime les idées derrière Simple. Cependant, des problèmes surviennent lorsque vous essayez d'utiliser HTTPS parce que Mamba supprime la fonctionnalité "intégrable" de Simple.
ThreaT
6

Ce code est meilleur que le nôtre, il vous suffit d'ajouter 2 bibliothèques : javax.servelet.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();
    }
}
leandro
la source
2
La question demande une solution purement Java SE. Vous constaterez que jetty implémente l'API Java EE.
Sridhar
Jetty fonctionne parfaitement avec Java SE standard et répond donc aux exigences. Il implémente des parties de l'API Java EE, il n'en a pas besoin . Il existe une différence.
David Tonhofer
1
Cela n'est pas admissible. "en utilisant uniquement l'API Java SE" . *.Servlet.jaret ne *.jetty.jarfont évidemment pas partie de Java SE.
icza
dois-je installer la jetée? ou puis-je simplement supprimer ces deux pots et exécuter ce fichier?
Paul Preibisch
4

Toutes les réponses ci-dessus fournissent des détails sur le gestionnaire de requêtes à thread unique principal.

réglage:

 server.setExecutor(java.util.concurrent.Executors.newCachedThreadPool());

Permet de servir plusieurs requêtes via plusieurs threads en utilisant le service exécuteur.

Ainsi, 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();
        }
    }
}
Balu mallisetty
la source
3

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!

Olu Smith
la source
2

Que diriez- vous du projet Apache Commons HttpCore ?

Depuis le 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 l'API
  • Petite empreinte mémoire (prévisible)
  • Bibliothèque autonome (pas de dépendances externes au-delà de JRE)
Iqbal
la source
C'est probablement trop bas. Il faut au moins viser une solution qui appelle votre code au niveau de l'API servlet, à moins que l'on ne veuille traiter seul tous les concepts comme le segmentage, l'encodage, etc. Cela peut être amusant cependant.
David Tonhofer
2

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.

  1. Il reçoit une demande du navigateur sous forme de texte
  2. Il analyse pour récupérer les informations 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 Response.javaclasse convertit une réponse brute en réponse 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;
}
Devashish Priyadarshi
la source
1

Vous pouvez écrire un serveur Java Jetty intégré assez simple .

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

Donc, si dans l'approche non intégrée, votre application Web intégrée au fichier WAR déployé sur un serveur externe ( Tomcat / Jetty / etc), dans la jetée intégrée, vous écrivez l'application Web et instanciez le serveur de la jetée dans la même base de code.

Un exemple de serveur Java Jetty intégré que vous pouvez git cloner et utiliser: https://github.com/stas-slu/embedded-jetty-java-server-example

Johnny
la source