простой HTTP-сервер в Java, использующий только API Java SE

333

Есть ли способ создать базовый HTTP-сервер (поддерживающий только GET / POST) в Java, используя только API Java SE, без написания кода для ручного разбора HTTP-запросов и ручного форматирования HTTP-ответов? Java SE API прекрасно инкапсулирует функциональность HTTP-клиента в HttpURLConnection, но есть ли аналог для функциональности HTTP-сервера?

Просто чтобы быть ясным, проблема, с которой я сталкиваюсь со многими примерами ServerSocket, которые я видел в Интернете, заключается в том, что они выполняют свои собственные синтаксический анализ / форматирование запросов и обработку ошибок, что утомительно, подвержено ошибкам и вряд ли будет всеобъемлющим, и я пытаюсь избежать этого по этим причинам.

В качестве примера ручной манипуляции HTTP, которую я пытаюсь избежать:

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

Аскер
источник
3
Ммм ... краткий ответ - нет. Если вам нужно что-то, что обрабатывает публикацию и получение запросов без ручной записи заголовков http, вы можете использовать сервлеты. Но это Java. Если вы не хотите использовать что-то подобное, сокеты и ручной синтаксический анализ - единственный другой вариант, который я знаю.
Мэтт Филлипс
3
Я знаю, что это не в духе SO, но я призываю вас пересмотреть свое отвращение к API Java EE. Как уже упоминалось в некоторых ответах, есть несколько очень простых реализаций, таких как Jetty, которые позволяют встроить веб-сервер в ваше автономное приложение, при этом все еще используя API сервлетов. Если по какой-то причине вы абсолютно не можете использовать API Java EE, не обращайте внимания на мой комментарий :-)
Крис Томпсон,
1
«Сервлеты» на самом деле не являются «Java EE». Это просто способ написания плагинов, которые могут вызываться окружающим приложением в ответ на активность сообщений (в наши дни, как правило, это HTTP-запросы). Обеспечение среды размещения сервлетов «с использованием только API Java SE» - это именно то, что делают Jetty и Tomcat. Конечно, вы можете отказаться от нежелательной сложности, но тогда вам может потребоваться выбрать подмножество разрешенных атрибутов и конфигураций GET / POST. Хотя зачастую это того не стоит, за исключением особых проблем с безопасностью и встроенными функциями.
Дэвид Тонхофер
1
Возможно, стоит пройти этот список http-серверов, прежде чем принимать решение. java-source.net/open-source/web-servers
ThreaT

Ответы:

469

Начиная с Java SE 6 в Sun Oracle JRE имеется встроенный HTTP-сервер . com.sun.net.httpserverРезюме пакета описывают задействованные классы и содержат примеры.

Вот начальный пример, скопированный из их документов (тем не менее, для всех, кто пытается его редактировать, потому что это уродливый кусок кода, пожалуйста, не копируйте, а не мой, более того, вы никогда не должны редактировать цитаты, если они не изменились. в первоисточнике). Вы можете просто скопировать и запустить его на Java 6+.

package com.stackoverflow.q3732109;

import java.io.IOException;
import java.io.OutputStream;
import java.net.InetSocketAddress;

import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;

public class Test {

    public static void main(String[] args) throws Exception {
        HttpServer server = HttpServer.create(new InetSocketAddress(8000), 0);
        server.createContext("/test", new MyHandler());
        server.setExecutor(null); // creates a default executor
        server.start();
    }

    static class MyHandler implements HttpHandler {
        @Override
        public void handle(HttpExchange t) throws IOException {
            String response = "This is the response";
            t.sendResponseHeaders(200, response.length());
            OutputStream os = t.getResponseBody();
            os.write(response.getBytes());
            os.close();
        }
    }

}

Следует отметить, что response.length()роль в их примере плохая, так и должно быть response.getBytes().length. Даже в этом случае getBytes()метод должен явно указывать кодировку, которую вы затем указываете в заголовке ответа. Увы, хотя и вводящий в заблуждение начинающих, в конце концов, это всего лишь базовый пример.

Выполните его и перейдите по адресу http: // localhost: 8000 / test, и вы увидите следующий ответ:

Это ответ


Что касается использования com.sun.*классов, обратите внимание, что это, в отличие от того, что думают некоторые разработчики, абсолютно не запрещено общеизвестными часто задаваемыми вопросами. Почему разработчики не должны писать программы, называющие «солнечные» пакеты . Этот FAQ касается sun.*пакета (такого как sun.misc.BASE64Encoder) для внутреннего использования Oracle JRE (который, таким образом, убьет ваше приложение при запуске его на другом JRE), а не com.sun.*пакета. Sun / Oracle также просто разрабатывает программное обеспечение поверх API Java SE, как и любая другая компания, такая как Apache и так далее. Использование com.sun.*классов не рекомендуется (но не запрещено), когда это касается реализации определенного API Java, такого как GlassFish (Java EE impl), Mojarra (JSF impl), Джерси (JAX-RS impl) и т. Д.

BalusC
источник
19
@Waldheinz: вроде как @Software ты путаешь sun.*с com.sun.*. Например, вы видите документацию по sun.*API? Посмотрите здесь: java.sun.com/products/jdk/faq/faq-sun-packages.html Это говорит о чем-нибудь com.sun.*? com.sun.*Используется только для их собственного общественного программного обеспечения , которое не является частью Java API. Они также разрабатывают программное обеспечение поверх Java API, как и любая другая компания.
BalusC
4
Я думаю, что это очень хороший http-сервер для использования в интеграционных тестах. спасибо за подсказку!
Андреас Петерссон
13
Если вы используете Eclipse и получаете сообщение об ошибке типа «Ограничение доступа: тип HttpExchange недоступен из-за ограничения на требуемую библиотеку ...», stackoverflow.com/a/10642163 рассказывает, как отключить эту проверку доступа.
Самули Пахаоха
13
FWIW это также присутствует в OpenJDK.
Джейсон С
6
Классы, упомянутые здесь, помечены @jdk.Exportedв исходном коде OpenJDK, что означает, что API считается общедоступным и будет доступен в Java 9 (некоторые другие com.sun.*пакеты станут недоступными из-за Project Jigsaw).
Жюль
42

Проверьте NanoHttpd

«NanoHTTPD - это легкий HTTP-сервер, разработанный для встраивания в другие приложения, выпущенный по модифицированной лицензии BSD.

Он разрабатывается в Github и использует Apache Maven для сборок и модульного тестирования ».

letronje
источник
4
Одно предостережение: вероятно, что NanoHTTPD не имеет защиты от атак по деревьям - вы должны проверить это, если он будет выступать по публичному адресу. Под этим я подразумеваю атаки, когда GET /../../blahblah http/1.1выдается подобный запрос, и сервер проходит над корнем веб-сайта и попадает в область системных файлов, обслуживая файлы, которые могут быть использованы для взлома или удаленной атаки на систему, например файл паролей.
Лоуренс Дол
7
Кажется, это исправлено. Текущая версия генерирует 403 if (uri.startsWith ("..") || uri.endsWith ("..") || uri.indexOf ("../")> = 0).
Лена Шиммель
5
Я не понимаю, как это ответ на этот вопрос.
Кимати
28

Решение com.sun.net.httpserver не переносится между JRE. Лучше использовать официальный API веб-сервисов в javax.xml.ws для загрузки минимального HTTP-сервера ...

import java.io._
import javax.xml.ws._
import javax.xml.ws.http._
import javax.xml.transform._
import javax.xml.transform.stream._

@WebServiceProvider
@ServiceMode(value=Service.Mode.PAYLOAD) 
class P extends Provider[Source] {
  def invoke(source: Source) = new StreamSource( new StringReader("<p>Hello There!</p>"));
}

val address = "http://127.0.0.1:8080/"
Endpoint.create(HTTPBinding.HTTP_BINDING, new P()).publish(address)

println("Service running at "+address)
println("Type [CTRL]+[C] to quit!")

Thread.sleep(Long.MaxValue)

РЕДАКТИРОВАТЬ: это на самом деле работает! Приведенный выше код выглядит как Groovy или что-то в этом роде. Вот перевод на Java, который я тестировал:

import java.io.*;
import javax.xml.ws.*;
import javax.xml.ws.http.*;
import javax.xml.transform.*;
import javax.xml.transform.stream.*;

@WebServiceProvider
@ServiceMode(value = Service.Mode.PAYLOAD)
public class Server implements Provider<Source> {

    public Source invoke(Source request) {
        return  new StreamSource(new StringReader("<p>Hello There!</p>"));
    }

    public static void main(String[] args) throws InterruptedException {

        String address = "http://127.0.0.1:8080/";
        Endpoint.create(HTTPBinding.HTTP_BINDING, new Server()).publish(address);

        System.out.println("Service running at " + address);
        System.out.println("Type [CTRL]+[C] to quit!");

        Thread.sleep(Long.MAX_VALUE);
    }
}
gruenewa
источник
1
+1 за переносимость. Жаль, что вы не можете установить тип содержимого ответа как есть text/xml.
icza
1
Я думаю, что вы могли бы сделать класс <code> Server реализует Provider <DataSource> {</ code> ... и затем указать Content-Type в методе <code> getContentType () </ code> DataSource. Кроме того, вы также можете ввести WebServiceContext: <code> @Resource WebServiceContext ctx; </ code>, чтобы установить другие заголовки и прочитать параметры запроса. К сожалению, установка типа контента через WebServiceContext не работает.
gruenewa
4
Не могли бы вы объяснить, почему com.sun.net.HttpServer не переносится между JRE, пожалуйста?
javabeangrinder
3
Нет, я так не думаю. Он не будет работать на Java-реализации IBM и, возможно, на других. И даже если это работает сейчас, внутренние API могут изменяться. Почему бы просто не использовать официальный API?
gruenewa
1
Эта ссылка: docs.oracle.com/javase/9/docs/api/java.xml.ws-summary.html говорит, что модуль java.xml.ws устарел с Java 9.
Эрл Сегал-Халеви,
23

Мне нравится этот вопрос, потому что это область, где постоянно происходят инновации, и всегда необходимо иметь легкий сервер, особенно когда речь идет о встроенных серверах в небольших (э) устройствах. Я думаю, что ответы делятся на две большие группы.

  1. Тонкий сервер : статический контент на сервере с минимальной обработкой, обработкой контекста или сеанса.
  2. Малый сервер : якобы a имеет много httpD-подобных серверных качеств с минимальной занимаемой площадью.

В то время как я мог бы считать, что HTTP-библиотеки, такие как: Jetty , Apache Http Components , Netty и другие, больше походят на необработанные средства обработки HTTP. Маркировка очень субъективна и зависит от того, что вам нужно для небольших сайтов. Я делаю это различие в духе вопроса, особенно замечание о ...

  • «... без написания кода для ручного разбора HTTP-запросов и ручного форматирования HTTP-ответов ...»

Эти необработанные инструменты позволяют вам сделать это (как описано в других ответах). Они на самом деле не поддаются готовому стилю создания легкого, встроенного или мини-сервера. Мини-сервер - это то, что может дать вам функциональность, аналогичную полнофункциональному веб-серверу (например, Tomcat). ) без наворотов, малой громкости, хорошей производительности в 99% случаев. Тонкий сервер кажется ближе к оригинальной фразировке чуть больше, чем простой, возможно, с ограниченной функциональностью подмножества, достаточной для того, чтобы вы выглядели хорошо в 90% случаев. Моя идея «сырого» бытия заставляла меня выглядеть хорошо 75–89% времени без лишнего дизайна и кодирования. Я думаю, что если / когда вы достигнете уровня WAR-файлов, мы оставим «маленький» для бонси-серверов, который выглядит как все, что большой сервер делает меньше.

Варианты тонкого сервера

Параметры мини-сервера:

  • Spark Java ... Хорошие вещи возможны с множеством вспомогательных конструкций, таких как Filters, Templates и т. Д.
  • MadVoc ... стремится быть бонсай и вполне может быть таким ;-)

Среди прочего, я бы хотел включить аутентификацию, валидацию, интернационализацию, использование чего-то вроде FreeMaker или другого инструмента шаблона для визуализации вывода страницы. В противном случае управление редактированием и параметризацией HTML может привести к тому, что работа с HTTP будет выглядеть как крестики-нолики. Естественно, все зависит от того, насколько гибким вам нужно быть. Если это факсимильный аппарат на основе меню, это может быть очень просто. Чем больше взаимодействий, тем « плотнее » должна быть ваша структура. Хороший вопрос, удачи!

воля
источник
21

Загляните на веб-сервер Jetty Jetty . Превосходная часть программного обеспечения с открытым исходным кодом, которое, казалось бы, отвечает всем вашим требованиям.

Если вы настаиваете на том, чтобы катиться самостоятельно, взгляните на класс «httpMessage».

Джеймс Андерсон
источник
Я думаю, что пристань API зависит от сервлета.
неопровержимый
4
@Irreputable: Нет, Jetty - это высокомодульный веб-сервер, в котором контейнер сервлетов является одним из дополнительных модулей.
Лоуренс Дол
«Это аналог для функциональности сервера» - да, это «сервлет» API. Контейнер сервлетов вызывает ваш класс после того, как он проанализировал заголовки, куки и т. Д.
Джеймс Андерсон
1
Просто для записи - Jetty поставляется с собственной реализацией Servlet API и прекрасно работает с Java SE
Джеймс Андерсон,
4
Причал слишком большой и имеет слишком много кривой обучения, прежде чем фактическое использование производства становится возможным.
ThreaT
18

Когда-то я искал что-то похожее - легкий, но полностью функциональный HTTP-сервер, который я мог бы легко встраивать и настраивать. Я нашел два типа потенциальных решений:

  • Полноценные серверы, которые не так уж легки или просты (для крайнего определения легковесности).
  • Действительно легковесные серверы, которые не совсем HTTP-серверы, но прославленные примеры ServerSocket, которые даже не соответствуют RFC удаленно и не поддерживают часто необходимые базовые функции.

Итак ... Я намеревался написать JLHTTP - облегченный HTTP-сервер Java .

Вы можете встроить его в любой проект в виде единого (если довольно длинного) исходного файла или в виде баночки ~ 50 КБ (без ~ 35 К) без каких-либо зависимостей. Он стремится быть RFC-совместимым и включает в себя обширную документацию и множество полезных функций, сохраняя при этом раздутость до минимума.

Возможности включают в себя: виртуальные хосты, обслуживание файлов с диска, сопоставления типов MIME через стандартный файл mime.types, генерацию индекса каталога, файлы приветствия, поддержку всех методов HTTP, поддержку условных ETag и заголовков If- *, кодирование передачи по частям, gzip / deflate сжатие, базовый HTTPS (как предусмотрено JVM), частичное содержимое (продолжение загрузки), обработка нескольких частей / данных формы для загрузки файлов, множественные обработчики контекста через API или аннотации, разбор параметров (строка запроса или x-www-form-urlencoded тело) и т. д.

Я надеюсь, что другие найдут это полезным :-)

amichair
источник
Основной метод является хорошим примером базового использования, и часто задаваемые вопросы входят во многие детали. Если у вас есть предложения по улучшению существующих документов, свяжитесь со мной напрямую!
amichair
8

Можно создать http-сервер, который обеспечивает базовую поддержку для сервлетов J2EE, используя только JDK и API сервлетов в нескольких строках кода.

Я нашел это очень полезным для модульного тестирования сервлетов, так как он запускается намного быстрее, чем другие легкие контейнеры (мы используем пристань для производства).

Большинство очень легких http-серверов не обеспечивают поддержку сервлетов, но они нам нужны, поэтому я решил поделиться.

Приведенный ниже пример предоставляет базовую поддержку сервлетов или throws и UnsupportedOperationException для вещей, которые еще не реализованы. Он использует com.sun.net.httpserver.HttpServer для базовой поддержки http.

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
источник
В нем отсутствуют некоторые методы для ServletOutputStream и ServletInputStream
HomeIsWhereThePcIs
более новая версия сервлета API, выше, подходит для 3.0 и ниже. Просто добавьте недостающие методы в пример
f.carlsen
6

Я настоятельно рекомендую заглянуть в Simple , особенно если вам не нужны возможности Servlet, а просто доступ к объектам request / reponse. Если вам нужен REST, вы можете поставить поверх него Джерси, если вам нужно вывести HTML или аналогичный, есть Freemarker. Я действительно люблю то, что вы можете сделать с этой комбинацией, и есть относительно мало API для изучения.

Waldheinz
источник
+1. Мне нравятся идеи, лежащие в основе Simple. Однако возникают проблемы при попытке использовать HTTPS, потому что Mamba убирает функцию «встраиваемости» из Simple.
ThreaT
6

Этот код лучше нашего, вам нужно всего лишь добавить 2 библиотеки: javax.servelet.jar и org.mortbay.jetty.jar .

Класс Причала:

package jetty;

import java.util.logging.Level;
import java.util.logging.Logger;
import org.mortbay.http.SocketListener;
import org.mortbay.jetty.Server;
import org.mortbay.jetty.servlet.ServletHttpContext;

public class Jetty {

    public static void main(String[] args) {
        try {
            Server server = new Server();
            SocketListener listener = new SocketListener();      

            System.out.println("Max Thread :" + listener.getMaxThreads() + " Min Thread :" + listener.getMinThreads());

            listener.setHost("localhost");
            listener.setPort(8070);
            listener.setMinThreads(5);
            listener.setMaxThreads(250);
            server.addListener(listener);            

            ServletHttpContext context = (ServletHttpContext) server.getContext("/");
            context.addServlet("/MO", "jetty.HelloWorldServlet");

            server.start();
            server.join();

        /*//We will create our server running at http://localhost:8070
        Server server = new Server();
        server.addListener(":8070");

        //We will deploy our servlet to the server at the path '/'
        //it will be available at http://localhost:8070
        ServletHttpContext context = (ServletHttpContext) server.getContext("/");
        context.addServlet("/MO", "jetty.HelloWorldServlet");

        server.start();
        */

        } catch (Exception ex) {
            Logger.getLogger(Jetty.class.getName()).log(Level.SEVERE, null, ex);
        }

    }
} 

Класс сервлетов:

package jetty;

import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class HelloWorldServlet extends HttpServlet
{
    @Override
    protected void doGet(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws ServletException, IOException
    {
        String appid = httpServletRequest.getParameter("appid");
        String conta = httpServletRequest.getParameter("conta");

        System.out.println("Appid : "+appid);
        System.out.println("Conta : "+conta);

        httpServletResponse.setContentType("text/plain");
        PrintWriter out = httpServletResponse.getWriter();
        out.println("Hello World!");
        out.close();
    }
}
Leandro
источник
2
Вопрос требует чисто Java SE решения. Вы обнаружите, что Jetty реализует API Java EE.
Шридхар
Jetty отлично работает с использованием стандартного Java SE и, следовательно, соответствует требованиям. Он реализует части API Java EE, ему это не нужно . Есть разница.
Дэвид Тонхофер
1
Это не соответствует требованиям. msgstr "используя только API Java SE" . *.Servlet.jarи *.jetty.jar, очевидно, не являются частью Java SE.
icza
мне нужно установить причал? или я могу просто отключить эти две банки и запустить этот файл?
Пол Прейбиш
4

Все вышеперечисленное подробно описывает детали обработки запросов с одним основным потоком.

установка:

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

Позволяет выполнять несколько запросов через несколько потоков, используя службу executor.

Таким образом, код конца будет примерно таким:

import java.io.IOException;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;
public class App {
    public static void main(String[] args) throws Exception {
        HttpServer server = HttpServer.create(new InetSocketAddress(8000), 0);
        server.createContext("/test", new MyHandler());
        //Thread control is given to executor service.
        server.setExecutor(java.util.concurrent.Executors.newCachedThreadPool());
        server.start();
    }
    static class MyHandler implements HttpHandler {
        @Override
        public void handle(HttpExchange t) throws IOException {
            String response = "This is the response";
            long threadId = Thread.currentThread().getId();
            System.out.println("I am thread " + threadId );
            response = response + "Thread Id = "+threadId;
            t.sendResponseHeaders(200, response.length());
            OutputStream os = t.getResponseBody();
            os.write(response.getBytes());
            os.close();
        }
    }
}
Балу маллисетты
источник
3

выписка Простой . это довольно простой встраиваемый сервер со встроенной поддержкой для самых разных операций. Особенно мне нравится его многопоточность модели ..

Удивительный!

Олу Смит
источник
2

Как насчет проекта Apache Commons HttpCore ?

С веб-сайта: ... HttpCore Цели

  • Реализация самых фундаментальных транспортных аспектов HTTP
  • Баланс между хорошей производительностью и ясностью и выразительностью API
  • Небольшой (предсказуемый) объем памяти
  • Автономная библиотека (без внешних зависимостей кроме JRE)
Икбал
источник
Это, вероятно, слишком низкий уровень. Нужно, по крайней мере, стремиться к решению, которое вызывает ваш код на уровне API сервлета, если только вы не хотите иметь дело со всеми такими понятиями, как разбиение на фрагменты, кодирование и т. Д. Самостоятельно. Это может быть весело, хотя.
Дэвид Тонхофер
2

Попробуйте это https://github.com/devashish234073/Java-Socket-Http-Server/blob/master/README.md

Этот API создает HTTP-сервер с использованием сокетов.

  1. Получает запрос от браузера в виде текста
  2. Анализирует его, чтобы получить информацию об URL, метод, атрибуты и т. Д.
  3. Создает динамический ответ, используя определенное сопоставление URL
  4. Отправляет ответ в браузер.

Например, вот как конструктор в Response.javaклассе преобразует необработанный ответ в ответ http:

public Response(String resp){
    Date date = new Date();
    String start = "HTTP/1.1 200 OK\r\n";
    String header = "Date: "+date.toString()+"\r\n";
    header+= "Content-Type: text/html\r\n";
    header+= "Content-length: "+resp.length()+"\r\n";
    header+="\r\n";
    this.resp=start+header+resp;
}
Деваши Приядарши
источник
1

Вы можете написать довольно простой встроенный Jetty Java-сервер .

Встроенный Jetty означает, что сервер (Jetty) поставляется вместе с приложением, а не развертывается на внешнем сервере Jetty.

Так что, если подход не встроен, ваше веб-приложение встроено в WAR-файл, который развернут на каком-то внешнем сервере ( Tomcat / Jetty / etc), во встроенном Jetty вы пишете веб-приложение и создаете экземпляр сервера Jetty в той же кодовой базе.

Примером для встроенного Java-сервера Jetty вы можете воспользоваться git clone и использовать: https://github.com/stas-slu/embedded-jetty-java-server-example

Джонни
источник