Простой HTTP-сервер на Java, использующий только Java SE API
Есть ли способ создать очень простой HTTP-сервер (поддерживающий только GET / POST) на Java, используя только Java SE API, без написания кода для ручного анализа HTTP-запросов и ручного форматирования HTTP-ответов? Java SE API прекрасно инкапсулирует функциональность HTTP-клиента в HttpURLConnection
, но есть ли аналог функциональности HTTP-сервера?
Просто для ясности, проблема, с которой я сталкиваюсь во многих ServerSocket
примерах, которые я видел онлайн, заключается в том, что они выполняют свой собственный синтаксический анализ запроса / форматирование ответа и обработку ошибок, что утомительно, подвержено ошибкам и вряд ли будет всеобъемлющим, и я пытаюсь избежать этого по этим причинам.
Переведено автоматически
Ответ 1
Начиная с Java SE 6, в Java есть встроенный HTTP-сервер Солнце Oracle JRE. Имя модуля Java 9 - jdk.httpserver
. В 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.*
пакета (такого как sun.misc.BASE64Encoder
) для внутреннего использования Oracle JRE (который, таким образом, убьет ваше приложение при запуске его на другом JRE), а не com.sun.*
пакета. Sun / Oracle также просто сами разрабатывают программное обеспечение поверх Java SE API, как и любая другая компания, такая как Apache и так далее. Более того, эта специфика HttpServer
должна присутствовать в каждом JDK, поэтому нет абсолютно никаких проблем с "переносимостью", как это могло бы произойти с sun.*
пакетом. Использование com.sun.*
классов только не рекомендуется (но не запрещено), когда это касается реализации определенного Java API, такого как GlassFish (Java EE impll), Mojarra (JSF impl), Jersey (JAX-RS impl) и т.д.
Ответ 2
Ознакомьтесь с NanoHttpd
NanoHttpd - это легкий HTTP-сервер, предназначенный для встраивания в другие приложения, выпущенный по модифицированной лицензии BSD.
Он разрабатывается на Github и использует Apache Maven для сборок и модульного тестирования "
Ответ 3
Решение com.sun.net.httpserver не переносится на JRES. Лучше использовать официальный webservices 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);
}
}
Ответ 4
Мне нравится этот вопрос, потому что это область, где постоянно внедряются инновации, и всегда есть потребность в легком сервере, особенно когда речь идет о встроенных серверах в небольших устройствах. Я думаю, что ответы можно разделить на две большие группы.
- Тонкий сервер: статический контент на сервере с минимальной обработкой контекста или сеанса.
- Small-server: якобы a обладает многими качествами сервера, подобными httpD, и занимает настолько мало места, насколько это возможно.
Хотя я мог бы рассмотреть HTTP-библиотеки, такие как: Jetty, Apache Http Components, Netty и другие, они больше похожи на необработанные средства обработки HTTP. Маркировка очень субъективна и зависит от того, какие функции вам приходилось выполнять для небольших сайтов. Я провожу это различие в духе вопроса, особенно замечания о...
- "... без написания кода для ручного анализа HTTP-запросов и ручного форматирования HTTP-ответов ..."
Эти необработанные инструменты позволяют вам сделать это (как описано в других ответах). На самом деле они не подходят для готового стиля создания легкого, встроенного или мини-сервера. Мини-сервер - это то, что может предоставить вам функциональность, аналогичную полнофункциональному веб-серверу (например, Tomcat), без наворотов, с низким объемом, хорошей производительностью в 99% случаев. Тонкий сервер кажется ближе к исходной формулировке, чуть больше, чем raw, возможно, с ограниченным набором функциональных возможностей, достаточных для того, чтобы вы выглядели хорошо в 90% случаев. Моя идея raw заключалась бы в том, чтобы я выглядел хорошо в 75-89% случаев без дополнительного дизайна и кодирования. Я думаю, что если / когда вы достигнете уровня файлов WAR, мы оставим "маленький" для серверов bonsi, который выглядит так, будто все, что делает большой сервер, меньше.
Параметры тонкого сервера
Опции мини-сервера:
- Spark Java ... Хорошие результаты возможны благодаря множеству вспомогательных конструкций, таких как фильтры, шаблоны и т.д.
- MadVoc ... стремится стать бонсай и вполне может стать таковым ;-)
Среди прочего, что следует учитывать, я бы включил аутентификацию, валидацию, интернационализацию, использование чего-то вроде FreeMaker или другого инструмента для создания шаблонов для отображения выходных данных страницы. В противном случае управление редактированием HTML и параметризацией, вероятно, сделает работу с HTTP похожей на крестики-нолики. Естественно, все зависит от того, насколько гибким вам нужно быть. Если это факсимильный аппарат с меню, он может быть очень простым. Чем больше взаимодействий, тем "толще" должен быть ваш фреймворк. Хороший вопрос, удачи!