Java SE API kullanarak Java'daki basit HTTP sunucusu


333

HTTP isteklerini manuel olarak ayrıştırmak ve HTTP yanıtlarını manuel olarak biçimlendirmek için kod yazmadan, Java'da yalnızca Java SE API kullanarak çok temel bir HTTP sunucusu (yalnızca GET / POST'u destekleyen) oluşturmanın bir yolu var mı? Java SE API HttpURLConnection'daki HTTP istemci işlevselliğini güzel bir şekilde içine alır, ancak HTTP sunucusu işlevselliği için bir analog var mı?

Açıkça söylemek gerekirse, çevrimiçi gördüğüm birçok ServerSocket örneğiyle yaşadığım sorun, yorucu, hataya eğilimli ve kapsamlı olması muhtemel olmayan kendi istek ayrıştırma / yanıt biçimlendirme ve hata işlemlerini gerçekleştirmeleri, ve bu nedenlerden kaçınmaya çalışıyorum.

Ben kaçınmaya çalışıyorum manuel HTTP manipülasyon örneği:

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


3
Hmm ... kısa cevap hayır. Http üstbilgilerini elle yazmadan gönderi işleyen ve istek alan bir şey istiyorsanız, sunucu uygulamaları kullanabilirsiniz. Ama bu java ee. Böyle bir şey kullanmak istemiyorsanız, soketler ve manuel ayrıştırma bildiğim diğer tek seçenektir.
Matt Phillips

3
Bunun SO'nun ruhunda olmadığını biliyorum, ama sizi Java EE API'leri için tatsızlık olarak yeniden düşünmenizi tavsiye ediyorum. Yanıtlardan bazılarının da belirttiği gibi, Jetty gibi, sunucu uygulamasının API'sinden yararlanmaya devam ederken tek başına uygulamanıza bir web sunucusu yerleştirmenize izin veren bazı çok basit uygulamalar vardır. Java EE API'sini kesinlikle herhangi bir nedenden dolayı kullanamıyorsanız, lütfen yorumumu dikkate almayın :-)
Chris Thompson

1
"Sunucu uygulamaları" gerçekten "Java EE" değildir. Bunlar, mesaj etkinliğine yanıt olarak çevredeki uygulama tarafından çağrılabilecek eklentiler yazmanın bir yoludur (bu günlerde, genellikle HTTP istekleri). "Sadece Java SE API kullanarak" bir sunucu uygulaması barındırma ortamı sağlamak Jetty ve Tomcat tam olarak bunu yapar. Tabii ki istenmeyen karmaşıklığı atmak isteyebilirsiniz, ancak daha sonra GET / POST'un izin verilen özelliklerinin ve yapılandırmalarının bir alt kümesine karar vermeniz gerekebilir. Özel güvenlik / gömülü problemler dışında genellikle buna değmez.
David Tonhofer

1
Bir karar vermeden önce bu http sunucuları listesini gözden geçirmeye değer olabilir. java-source.net/open-source/web-servers
Tehdit

Yanıtlar:


469

Java SE 6'dan bu yana, Sun Oracle JRE'de yerleşik bir HTTP sunucusu var . com.sun.net.httpserverPaket özeti dahil sınıfları özetliyor ve örnekler içerir.

İşte dokümanlarından kopyalanmış bir başlangıç ​​örneği (yine de düzenlemeye çalışan tüm insanlara, çünkü çirkin bir kod parçası, lütfen yapmayın, bu benim değil kopya kopyasıdır, ayrıca değiştirilmedikçe alıntıları asla düzenlememelisiniz orijinal kaynakta). Java 6 + 'da kopyalayıp kopyalayabilirsiniz.

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

}

O olmalıdır Kaydetti response.length()onların örnekte kısım kötü, o olmalıydı response.getBytes().length. O zaman bile, getBytes()yöntem, daha sonra yanıt başlığında belirttiğiniz karakter kümesini açıkça belirtmelidir. Ne yazık ki, yeni başlayanlara yanlış yönlendirmeye rağmen, sonuçta sadece temel bir başlama örneği.

Yürütün ve http: // localhost: 8000 / test adresine gidin , aşağıdaki yanıtı göreceksiniz:

Bu cevap


com.sun.*Sınıfları kullanmaya gelince , bunun bazı geliştiricilerin düşündüklerinin aksine, iyi bilinen SSS tarafından neden kesinlikle yasaklanmadığını unutmayın.Geliştiriciler neden 'güneş' paketleri diyen programlar yazmamalıdır . Bu SSS , Oracle JRE tarafından dahili kullanım amaçlı sun.*paketle (örneğin sun.misc.BASE64Encoder, uygulamanızı com.sun.*paketle değil, farklı bir JRE'de çalıştırdığınızda öldürür) ilgilidir . Sun / Oracle, Apache gibi diğer tüm şirketler gibi Java SE API'nin üstünde de yazılım geliştirir. Kullanılması com.sun.*bir ilgili olduğunda sınıfları sadece (yasak değil) önerilmez uygulanmasını böyle GlassFish'in (Java EE impl), Mojarra (JSF impl), Jersey (JAX-RS impl) olarak vs belli bir Java API,


19
@Waldheinz: gibi @Software gibi karıştırıyorsun sun.*ile com.sun.*. Örneğin, sun.*API ile ilgili herhangi bir belge görüyor musunuz? Buraya bakın: java.sun.com/products/jdk/faq/faq-sun-packages.html Bir şey anlatıyor com.sun.*mu? com.sun.*Sadece Java API parçası olmayan, kendi kamu yazılım için kullanılır. Ayrıca her şirkette olduğu gibi Java API'sinin üzerinde yazılım geliştirirler.
BalusC

4
Ben bu entegrasyon test durumlarda kullanmak için çok güzel bir http sunucusu olduğunu düşünüyorum. ipucu için teşekkürler!
Andreas Petersson

13
Eclipse kullanıyorsanız ve "Erişim kısıtlaması: Gerekli kitaplıktaki kısıtlama nedeniyle HttpExchange türüne erişilemiyor ..." gibi bir hata alırsanız, stackoverflow.com/a/10642163 bu erişim denetiminin nasıl devre dışı bırakılacağını anlatır.
Samuli Pahaoja

13
FWIW bu OpenJDK'da da mevcuttur.
Jason C

6
Burada atıfta bulunulan sınıflar @jdk.ExportedOpenJDK kaynak kodunda etiketlenmiştir , bu da API'nin herkese açık olduğu ve Java 9'da kullanılabileceği anlamına gelir ( com.sun.*Project Jigsaw nedeniyle diğer bazı paketler kullanılamayacaktır).
Jules

42

Check out NanoHttpd

"NanoHTTPD, Modifiye BSD lisansı altında yayınlanan diğer uygulamalara gömmek için tasarlanmış hafif bir HTTP sunucusudur.

Github'da geliştiriliyor ve yapı ve birim testi için Apache Maven kullanıyor "


4
Dikkat edilmesi gereken nokta: NanoHTTPD'nin ağaç yürüme saldırılarına karşı koruması yoktur - genel bir adrese sunulacaksa bunu kontrol etmelisiniz. Bununla, bir isteğin yapıldığı GET /../../blahblah http/1.1ve sunucunun web sitesi kökünün üzerinde ve sistem dosyası arazisine yürüdüğü, bir şifre dosyası gibi sisteme zarar vermek veya uzaktan saldırmak için kullanılabilecek dosyaları sunan saldırıları kastediyorum .
Lawrence Dol

7
Sabit gibi görünüyor. Mevcut sürüm 403 if (uri.startsWith ("..") || uri.endsWith ("..") || uri.indexOf ("../")> = 0) oluşturur.
Lena Schimmel

5
Bunun bu soruya nasıl bir cevap olduğunu anlamıyorum.
kimathie

28

Com.sun.net.httpserver çözüm JRE genelinde taşınabilir değildir. Minimum bir HTTP sunucusunu önyüklemek için javax.xml.ws içindeki resmi web hizmetleri API'sını kullanmak daha iyidir ...

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: bu gerçekten işe yarıyor! Yukarıdaki kod Groovy veya benzeri bir şeye benziyor. İşte ben test Java için bir çeviri:

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
Taşınabilir olmak için +1. Yanıt içeriği türünü olduğu gibi ayarlayamamanız çok kötü text/xml.
icza

1
<code> Sınıf Sunucu uygulayabilir <DataSource> {</code> ... uygular ve sonra DataSource <code> getContentType () </code> yöntemi içinde içerik türü belirtebilirsiniz düşünüyorum. Ayrıca, diğer başlıkları ayarlamak ve istek parametrelerini okumak için WebServiceContext: <code> @Resource WebServiceContext ctx; </code> 'ı da enjekte edebilirsiniz. Maalesef içerik türünü WebServiceContext üzerinden ayarlamak işe yaramıyor.
gruenewa

4
Com.sun.net.HttpServer'ın neden JRE'lerde taşınabilir olmadığını açıklayabilir misiniz?
javabeangrinder

3
Hayır, sanmıyorum. IBM'in Java uygulaması ve belki de diğerleri üzerinde çalışmayacaktır. Ve şimdi çalışıyor olsa bile, dahili API'lerin değişmesine izin verilir. Neden sadece resmi API'yi kullanmıyorsunuz?
gruenewa

1
Bu bağlantı: docs.oracle.com/javase/9/docs/api/java.xml.ws-summary.html , java.xml.ws modülünün Java 9'dan beri kullanımdan kaldırıldığını söylüyor
Erel Segal-Halevi

23

Bu soruyu seviyorum, çünkü bu sürekli yeniliklerin olduğu bir alan ve özellikle küçük (er) cihazlardaki gömülü sunuculardan bahsederken her zaman hafif bir sunucuya ihtiyaç duyuluyor. Bence cevaplar iki geniş gruba ayrılıyor.

  1. İnce sunucu : minimum işlem, bağlam veya oturum işlemesi ile sunucu içerikli statik içerik.
  2. Küçük sunucu : Görünüşe göre a, kaçabileceğiniz kadar az yer kaplayan birçok httpD benzeri sunucu kalitesine sahiptir.

Jetty , Apache Http Components , Netty ve diğerleri gibi HTTP kitaplıklarını daha çok ham HTTP işleme olanaklarına benzetebilirim. Etiketleme çok özneldir ve küçük siteler için yayınlanmak üzere aradığınız şeylere bağlıdır. Bu ayrımı sorunun ruhunda yapıyorum, özellikle ...

  • "... HTTP isteklerini elle ayrıştırmak ve HTTP yanıtlarını elle biçimlendirmek için kod yazmadan ..."

Bu ham araçlar bunu yapmanızı sağlar (diğer cevaplarda açıklandığı gibi). Kendilerini gerçekten hafif, gömülü veya mini bir sunucu yapma hazır setine borç vermiyorlar. Mini sunucu, çan ve ıslık olmadan tam işlevli bir web sunucusuna (örneğin Tomcat gibi ) benzer işlevsellik verebilen bir şeydir , düşük ses seviyesi, iyi performans% 99 zaman. İnce bir sunucu, orijinal ifadeye, belki de sınırlı bir alt küme işlevselliği ile hamdan biraz daha fazla görünüyor, bu da zamanın% 90'ını iyi göstermenizi sağlayacak kadar. Benim ham fikrim, ekstra tasarım ve kodlama olmadan zamanın% 75 -% 89'unun iyi görünmesini sağlayacak. Bence / WAR dosyaları seviyesine ulaştığınızda, büyük bir sunucunun daha küçük yaptığı her şeye benzeyen bonsi sunucuları için "küçük" bıraktık.

İnce sunucu seçenekleri

Mini sunucu seçenekleri:

  • Spark Java ... Filtreler, Şablonlar vb.Gibi birçok yardımcı yapı ile iyi şeyler mümkündür.
  • MadVoc ... bonsai olmayı hedefliyor ve böyle olabilir ;-)

Dikkate alınacak diğer şeylerin yanı sıra, kimlik doğrulaması, doğrulama, uluslararasılaştırma, sayfa çıktısını oluşturmak için FreeMaker veya başka bir şablon aracı gibi bir şey kullanmayı da içerirdim . Aksi takdirde, HTML düzenleme ve parametrelendirmenin yönetilmesi, HTTP ile çalışmanın noughts-n-crosses gibi görünmesini sağlar. Doğal olarak, ne kadar esnek olmanız gerektiğine bağlı. Menü odaklı bir FAKS makinesi ise çok basit olabilir. Etkileşimler ne kadar fazla olursa , çerçeveniz o kadar kalın olur. İyi soru, iyi şanslar!


21

"İskele" web sunucusu İskelesi bir göz atın . Tüm gereksinimlerinizi karşılayan mükemmel bir Açık Kaynak yazılım parçası.

Eğer kendi yuvarlanma konusunda ısrar ediyorsanız "httpMessage" sınıfına bir göz atın.


Bence iskele api sunucu uygulamasına bağlı.
doldurulamaz

4
@Irreputable: Hayır, Jetty, isteğe bağlı modüllerinden biri olarak sunucu uygulaması kapsayıcısı olan oldukça modüler bir web sunucusudur.
Lawrence Dol

"orada sunucu işlevselliği için bir analog" - evet onun "sunucu uygulaması" API. Sunucu uygulaması kapsayıcısı, başlıkları, çerezleri vb. Ayrıştırdıktan sonra sınıfınızı arar
James Anderson

1
Sadece rekor için - Jetty kendi Servlet API uygulamasını ile geliyor ve Java SE ile gayet iyi çalışıyor
James Anderson

4
İskele, gerçek üretim kullanımı bir olasılık haline gelmeden önce çok büyük ve çok fazla öğrenme eğrisine sahip.
Mart'ta Tehdit

18

Bir zamanlar benzer bir şey arıyordum - kolayca gömüp özelleştirebileceğim hafif ama tamamen işlevsel bir HTTP sunucusu. İki tür potansiyel çözüm buldum:

  • Bu kadar hafif veya basit olmayan tam sunucular (aşırı hafifliğin tanımı için).
  • Tamamen HTTP sunucusu olmayan gerçekten hafif sunucular, ancak uzaktan RFC uyumlu bile olmayan ve yaygın olarak ihtiyaç duyulan temel işlevleri desteklemeyen yüceltilmiş ServerSocket örnekleri.

Yani ... JLHTTP - Java Hafif HTTP Sunucusu yazmak için yola çıktım .

Herhangi bir projeye tek bir (oldukça uzunsa) kaynak dosyası ya da bağımlılığı olmayan ~ 50K kavanoz (~ 35K soyulmuş) olarak gömebilirsiniz. RFC uyumlu olmaya çalışır ve şişkinliği minimumda tutarken kapsamlı belgeler ve birçok kullanışlı özellik içerir.

Özellikler: sanal ana bilgisayarlar, diskten dosya sunma, standart mime.types dosyası aracılığıyla mime tipi eşlemeler, dizin dizini oluşturma, karşılama dosyaları, tüm HTTP yöntemleri için destek, koşullu ETags ve If- * başlık desteği, yığın aktarım kodlaması, gzip / deflate sıkıştırma, temel HTTPS (JVM tarafından sağlanan şekilde), kısmi içerik (indirme devam), dosya yüklemeleri için çok parçalı / form verisi işleme, API veya ek açıklamalar yoluyla çoklu bağlam işleyicileri, parametre ayrıştırma (sorgu dizesi veya x-www-form-urlencoded vücut) vb.

Umarım diğerleri faydalı bulur :-)


Ana yöntem temel kullanım için iyi bir örnektir ve SSS ayrıntıların çoğuna girer. Mevcut dokümanları iyileştirmek için önerileriniz varsa, doğrudan benimle iletişime geçmekten çekinmeyin!
amichair



8

Sadece JDK ve servlet api ile J2EE sunucu uygulamaları için sadece birkaç satırlık kodda temel destek sağlayan bir httpserver oluşturmak mümkündür.

Bunu diğer hafif konteynerlerden çok daha hızlı başladığı için (birim üretim iskelesi kullanıyoruz) birim test sunucuları için çok yararlı buldum.

Çoğu çok hafif httpservers sunucu uygulamaları için destek sağlamaz, ancak onlara ihtiyacımız var, bu yüzden paylaşacağımı düşündüm.

Aşağıdaki örnek, henüz uygulanmayan şeyler için temel sunucu uygulaması desteği veya atar ve UnsupportedOperationException sağlar. Temel http desteği için com.sun.net.httpserver.HttpServer öğesini kullanır.

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

Bu, ServletOutputStream ve ServletInputStream'de bazı yöntemler eksik
HomeIsWhereThePcIs

daha yeni sürümü, yukarıdaki 3.0 ve aşağıya uyar. Sadece örneğe gerektiği gibi eksik methdos ekleyin
f.carlsen

6

İçine bakmanızı şiddetle tavsiye ederim Basit bakmanızı Eğer Servlet yetenekleri ama istek / yanıtı nesnelere sadece erişime gerek yoktur, özellikle eğer. REST'e ihtiyacınız varsa, bunun üzerine Jersey koyabilirsiniz, HTML veya benzeri bir çıktı almanız gerekiyorsa Freemarker var. Bu kombinasyonla neler yapabileceğinizi gerçekten çok seviyorum ve öğrenecek nispeten az API var.


+1. Simple'ın arkasındaki fikirleri seviyorum. Ancak, Mamba "katıştırılabilir" özelliğini Simple'dan kaldırdığı için HTTPS kullanmaya çalışırken sorunlar ortaya çıkar.
Mart'ta Tehdit

6

Bu kod bizimkinden daha iyi, sadece 2 libs eklemeniz gerekiyor: javax.servelet.jar ve org.mortbay.jetty.jar .

Sınıf İskelesi:

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

    }
} 

Servlet sınıfı:

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
Soru tamamen Java SE çözümü istiyor. İskelenin Java EE API'sini uyguladığını göreceksiniz.
Sridhar

İskele standart Java SE kullanarak mükemmel çalışır ve bu nedenle gereksinimlere uyar. Bu uygulayan Java EE API parçaları, bu olmaz gerek onu. Bir fark var.
David Tonhofer

1
Bu hak kazanmıyor. "sadece Java SE API kullanarak" . *.Servlet.jarve *.jetty.jarelbette Java SE'nin bir parçası değildir.
icza

iskeleyi ayarlamam gerekir mi? ya da sadece bu iki kavanozun kilidini açıp bu dosyayı çalıştırabilir miyim?
Paul Preibisch


4

Yukarıdaki tüm cevaplar Tek ana dişli Talep İşleyici hakkında detaylar.

ayar:

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

Yürütücü hizmetini kullanarak birden çok iş parçacığı üzerinden birden çok istek sunumuna izin verir.

Yani bitiş kodu aşağıdaki gibi bir şey olacaktır:

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

ödeme Basit . oldukça çeşitli işlemler için yerleşik destek ile oldukça basit bir gömülebilir sunucu. Özellikle iş parçacığı modelini seviyorum.

İnanılmaz!



2

Apache Commons HttpCore projesine ne dersiniz ?

Web sitesinden: ... HttpCore Hedefler

  • En temel HTTP aktarım yönlerinin uygulanması
  • İyi performans ile API'nın netliği ve ifade edilebilirliği arasındaki denge
  • Küçük (öngörülebilir) bellek alanı
  • Kendi kendine yeten kütüphane (JRE dışında dışa bağımlılık yok)

Bu muhtemelen çok düşük seviyededir. Kişi en azından kodlama, kodlama vb. Gibi tüm kavramlarla ilgilenmek istemediği sürece, kodunuzu sunucu uygulaması API düzeyinde çağıran bir çözüm hedeflemelidir. Yine de eğlenceli olabilir.
David Tonhofer

2

Bunu dene https://github.com/devashish234073/Java-Socket-Http-Server/blob/master/README.md

Bu API, soketleri kullanarak bir HTTP sunucusu oluşturur.

  1. Tarayıcıdan metin olarak bir istek alır
  2. URL bilgilerini, yöntemi, özellikleri vb. Almak için ayrıştırır.
  3. Tanımlanan URL eşlemesini kullanarak dinamik yanıt oluşturur
  4. Yanıtı tarayıcıya gönderir.

Örneğin, Response.javasınıftaki yapıcı işlenmemiş bir yanıtı http yanıtına şu şekilde dönüştürür:

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

Oldukça basit bir gömülü İskele yazabilirsiniz Java sunucusu .

Gömülü İskele, uygulamayı harici İskele sunucusuna dağıtmak yerine sunucunun (İskele) uygulamayla birlikte gönderildiği anlamına gelir.

Dolayısıyla, gömülü olmayan bir yaklaşımda web uygulamanız bazı harici sunuculara dağıtılan WAR dosyasına yerleştirilmişse ( Tomcat / Jetty / etc) , gömülü İskelede, web uygulamasını yazar ve iskele sunucusunu aynı kod tabanına başlatırsınız.

Gömülü Jetty Java sunucusu için bir örnek klon atabilir ve kullanabilirsiniz: https://github.com/stas-slu/embedded-jetty-java-server-example

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.