простий сервер HTTP на Java, використовуючи лише Java SE API


333

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

Щоб було зрозуміло, проблема, яку я маю з великою кількістю прикладів ServerSocket, яку я бачив в Інтернеті, полягає в тому, що вони роблять свій власний аналіз запиту / форматування відповіді та обробку помилок, що є стомлюючим, схильним до помилок і, швидше за все, не буде всебічним, і я намагаюся уникнути цього з тих причин.

Як приклад ручного маніпулювання HTTP, якого я намагаюся уникати:

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


3
Гм ... коротка відповідь - ні. Якщо ви хочете щось, що обробляє повідомлення та отримувати запити, не вручну писати заголовки http, тоді ви можете використовувати сервлети. Але це java ee. Якщо ви не хочете використовувати щось подібне, тоді розетки та ручний розбір - це єдиний інший варіант, про який я знаю.
Метт Філліпс

3
Я знаю, що це не в дусі SO, але я б закликав вас переглянути ваше неприязнь до API Java EE. Як зазначалося в деяких відповідях, є кілька прямолінійних реалізацій, таких як Jetty, які дозволяють вам вставляти веб-сервер у автономний додаток, використовуючи при цьому сервісні api. Якщо ви абсолютно не можете використовувати API Java EE з якоїсь причини, ніж будь ласка, ігноруйте мій коментар :-)
Кріс Томпсон,

1
"Сервлети" насправді не є "Java EE". Вони є лише способом написання плагінів, які можуть викликати навколишній додаток у відповідь на активність повідомлення (ці дні, як правило, HTTP-запити). Забезпечення середовища хостингу сервлетів, "використовуючи тільки Java SE API" - саме те, що роблять 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 також просто розробляють програмне забезпечення на вершині Java SE API, як і будь-яка інша компанія, така як Apache тощо. Використання com.sun.*класів відлякує (але не заборонено) лише тоді, коли це стосується реалізації певного Java API, наприклад GlassFish (Java EE impl), Mojarra (JSF impl), Джерсі (JAX-RS impl) тощо.


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.
Джейсон C

6
Класи, про які йдеться тут, позначені @jdk.Exportedу вихідному коді OpenJDK, що означає, що API вважається загальнодоступним та буде доступний на Java 9 (деякі інші com.sun.*пакети стануть недоступними через Jigsaw Project).
Жуль

42

Ознайомтеся з NanoHttpd

"NanoHTTPD - це невеликий HTTP-сервер, призначений для вбудовування в інші додатки, випущений за ліцензією Modified BSD.

Він розробляється в Github і використовує Apache Maven для побудови та тестування блоків "


4
Одне застереження: Ймовірно, що NanoHTTPD не має захисту від атак, що гуляють по деревах - вам слід перевірити це, чи буде воно подаватися на загальнодоступну адресу. Під цим я маю на увазі атаки, коли такий запит GET /../../blahblah http/1.1видається, і сервер заходить над коренем веб-сайту і перебуває в системному файлі, подаючи файли, які можна використовувати для компрометації або віддаленої атаки на систему, як файл пароля.
Лоуренс Дол

7
Це, здається, виправлено. Поточна версія генерує 403, якщо (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)

EDIT: це насправді працює! Наведений вище код схожий на 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);
    }
}

1
+1 за переносність. Як шкода, ви не можете встановити тип вмісту відповіді таким, яким він є text/xml.
icza

1
Я думаю, ви можете зробити <code> клас Сервер реалізує постачальника <DataSource> {</code> ..., а потім вказати Тип вмісту в методі <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, ми залишили "маленький" для серверів bonsi, який виглядає так, як все, що робить великий сервер, менше.

Параметри тонких серверів

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

  • Іскрована Java ... Гарні речі можливі завдяки безлічі допоміжних конструкцій, таких як Фільтри, Шаблони тощо.
  • MadVoc ... прагне бути бонсаєм і цілком може бути таким ;-)

Серед іншого, що слід врахувати, я б включив аутентифікацію, перевірку, інтернаціоналізацію, використовуючи щось на зразок FreeMaker або інший інструмент шаблону для відображення виводу сторінки. В іншому випадку управління HTML редагуванням та параметризацією, ймовірно, зробить роботу з HTTP схожим на noughts-n-crosss. Природно, все залежить від того, наскільки потрібно бути гнучким. Якщо це факсимільна машина, керована меню, це може бути дуже просто. Чим більше взаємодій, тим " товстішими " повинні бути ваші рамки. Добре запитання, удачі!


21

Погляньте на веб-сервер "Jetty" Jetty . Чудовий фрагмент програмного забезпечення з відкритим кодом, який, здається, відповідає всім вашим вимогам.

Якщо ви наполягаєте на прокату свого, тоді перегляньте клас "httpMessage".


Я думаю, що причал api залежить від сервлета.
незаперечний

4
@Irreputable: Ні, Jetty - це високомодульний веб-сервер, на якому є контейнер сервлетів як один із його додаткових модулів.
Лоуренс Дол,

"є аналогом функціональності сервера" - так, це "сервлет" API. Контейнер сервлетів викликає ваш клас після того, як він проаналізував заголовки, файли cookie тощо
Джеймс Андерсон,

1
Тільки для запису - Jetty поставляється з власною реалізацією API Servlet і працює чудово з Java SE
James Anderson

4
Jetty занадто великий і має занадто багато кривої навчання, перш ніж фактичне використання виробництва стане можливим.
Погроза

18

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

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

Отже ... я вирішив написати JLHTTP - легкий сервер HTTP на Java .

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

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

Я сподіваюся, що інші вважають його корисним :-)


Основний метод є хорошим прикладом базового використання, а FAQ задаються багатьма деталями. Якщо у вас є пропозиції щодо вдосконалення існуючих документів, не соромтесь зв’язатися зі мною безпосередньо!
amichair



8

Можна створити httpserver, який забезпечує основну підтримку сервлетів J2EE лише за допомогою JDK та api сервлетів у кількох рядках коду.

Я вважаю це дуже корисним для тестування сервлетів, оскільки воно запускається набагато швидше, ніж інші легкі контейнери (для виробництва ми використовуємо пристани).

Більшість дуже легких httpservers не підтримують сервлетів, але вони нам потрібні, тому я подумав, що поділюсь.

Наведений нижче приклад надає базову підтримку сервлетів, або кидків та 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());
    }
}

Цього методу не вистачає на ServletOutputStream і ServletInputStream
HomeIsWhereThePcIs

новіша версія сервілету-api, що відповідає версії 3.0 і нижче. Просто додайте відсутні приклади, як потрібно, у приклад
f.carlsen

6

Я настійно рекомендую заглянути в Simple , особливо якщо вам не потрібні можливості сервлетів, а просто доступ до об'єктів запиту / відгуку. Якщо вам потрібен REST, ви можете поставити Джерсі поверх нього, якщо вам потрібно вивести HTML або подібне, є Freemarker. Мені дуже подобається, що ви можете зробити з цією комбінацією, і API достатньо мало, щоб навчитися.


+1. Мені подобаються ідеї, що стоять за простою. Однак виникають проблеми при спробі використання HTTPS, оскільки Mamba забирає функцію "вбудовування" у Simple.
Погроза

6

Цей код кращий за наш, вам потрібно лише додати 2 libs: javax.servelet.jar та org.mortbay.jetty.jar .

Клас Jetty:

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

2
Питання задає суто рішення Java SE. Ви побачите, що jetty реалізує API Java EE.
Шрідхар

Jetty ідеально працює, використовуючи стандартний Java SE, і тому відповідає вимогам. Він реалізує частини API Java EE, він не потрібен . Є різниця.
Девід Тонхофер

1
Це не кваліфікується. "використовуючи тільки Java SE API" . *.Servlet.jarі *.jetty.jar, очевидно, не є частиною Java SE.
icza

мені потрібно налаштувати пристань? чи я можу просто відключити ці дві банки і запустити цей файл?
Пол Прейбіш


4

Усі вищевикладені відповіді на деталі про Один обробник запиту з основною різьбою.

налаштування:

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

Дозволяє подавати кілька запитів через декілька потоків за допомогою служби виконавця.

Таким чином, кінцевий код буде приблизно таким:

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 / тощо), у вбудований Jetty, ви пишете webapp та інстанціюєте сервер jetty в тій же базі коду.

Прикладом вбудованого сервера Jetty Java ви можете отримати клонування та використовувати: https://github.com/stas-slu/embedded-jetty-java-server-example

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.