373 votes

serveur HTTP simple en Java en utilisant uniquement les API Java SE

Est-il un moyen de créer un très de base du serveur HTTP (soutien à la seule GET/POST) en Java, en utilisant seulement l'API Java SE, sans écrire de code manuellement analyser les requêtes HTTP et la mise en forme manuelle des réponses HTTP? L'API Java SE bien encapsule le client HTTP fonctionnalité dans HttpURLConnection, mais est-il un analogue pour le serveur HTTP de la fonctionnalité?

Juste pour être clair, le problème que j'ai avec beaucoup de ServerSocket les exemples que j'ai vu en ligne, c'est qu'ils font de leur propre demande d'analyse/mise en forme de la réponse et les erreurs de manipulation, ce qui est fastidieux, source d'erreurs, et ne risquent pas d'être exhaustif, et j'essaie de l'éviter pour ces raisons.

Comme un exemple de manuel HTTP manipulation que j'essaie d'éviter:

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

526voto

BalusC Points 498232

Depuis la version 1.6 de Java, il y a un builtin HTTP serveur Sun Oracle JDK (note: le JDK, pas de JRE). L' com.sun.net.httpserver package résumé décrit les classes et contient des exemples.

Voici une (de base) kickoff exemple basé sur les docs, vous pouvez simplement copier "" coller'n'run sur la version 1.6 de Java

package com.example;

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 {
        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();
        }
    }

}

(a noté que l' response.length() part leur exemple est mauvais, il devrait mieux ont été response.getBytes().length; même alors, l' getBytes() méthode devez explicitement spécifier le jeu de caractères que vous spécifiez dans l'en-tête de réponse; hélas, c'est, après tout juste une base de lancement pour exemple)

Exécuter et aller en http://localhost:8000/test et vous verrez la réponse suivante:

C'est la réponse

Notez que c'est, contrairement à ce que certains naïfs dans l'esprit des développeurs, absolument pas interdit par la bien connue FAQ Pourquoi les Développeurs ne Doivent Pas Écrire des Programmes Qui Appellent le "soleil" des Paquets. Cette FAQ concerne l' sun.* ( sun.misc.BASE64Encoder) pour une utilisation interne par l'Oracle JRE, pas le com.sun.* package. Sun/Oracle aussi simplement développe des logiciels sur le dessus de l'API Java SE eux-mêmes, comme toutes les autres entreprises telles que Apache et ainsi de suite.

50voto

letronje Points 3228

Découvrez NanoHttpd

29voto

gruenewa Points 708

La solution de com.sun.net.httpserver n’est pas portable à travers JREs. Son mieux d’utiliser les webservices officiels API dans javax.xml.ws pour démarrer un serveur HTTP minimal...

EDIT : cela fonctionne réellement ! Le code ci-dessus ressemble à Groovy ou quelque chose. Voici une traduction à Java que j’ai testé :

25voto

James Anderson Points 18253

Jetez un oeil sur le serveur de web « Jetée » jetée. Superbe pièce de logiciel Open Source qui semble répondre à toutes vos exigences.

Si vous insistez pour rouler votre propre puis jetez un oeil à la classe « httpMessage ».

8voto

f.carlsen Points 123

Il est possible de créer un serveur http qui fournit un support de base pour J2EE, servlets avec juste le JDK et de la servlet api en seulement quelques lignes de code.

J'ai trouvé cela très utile pour les tests unitaires servlets, comme il démarre beaucoup plus vite que les autres léger conteneurs (nous utilisons la jetée pour la production).

La plupart des très léger httpservers ne fournissons pas de support pour les servlets, mais nous avons besoin d'eux, alors j'ai pensé que je devais partager.

L'exemple ci-dessous fournit à base de servlet de soutien, ou des lancers et des UnsupportedOperationException pour des trucs pas encore mis en œuvre. Il utilise le com.soleil.net.httpserver.HttpServer pour le http de base de soutien.

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());
    }
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X