server HTTP sederhana di Java hanya menggunakan Java SE API

333

Apakah ada cara untuk membuat server HTTP yang sangat mendasar (hanya mendukung GET / POST) di Jawa hanya menggunakan Java SE API, tanpa menulis kode untuk mengurai permintaan HTTP secara manual dan memformat respons HTTP secara manual? Java SE API dengan baik merangkum fungsionalitas klien HTTP di HttpURLConnection, tetapi apakah ada analog untuk fungsionalitas server HTTP?

Untuk lebih jelasnya, masalah yang saya miliki dengan banyak contoh ServerSocket yang saya lihat online adalah bahwa mereka melakukan parsing / format respons permintaan sendiri dan penanganan kesalahan, yang membosankan, rawan kesalahan, dan tidak cenderung komprehensif, dan saya berusaha menghindarinya karena alasan itu.

Sebagai contoh manipulasi HTTP manual yang saya coba hindari:

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

penanya
sumber
3
Umm ... jawaban singkatnya adalah tidak. Jika Anda menginginkan sesuatu yang menangani posting dan mendapatkan permintaan tanpa secara manual menulis header http maka Anda bisa menggunakan servlet. Tapi itu java ee. Jika Anda tidak ingin menggunakan sesuatu seperti itu maka soket dan penguraian manual adalah satu-satunya pilihan lain yang saya tahu.
Matt Phillips
3
Saya tahu ini bukan dalam semangat SO, tapi saya ingin Anda mempertimbangkan kembali ketidaksukaan Anda terhadap Java EE API. Seperti beberapa jawaban telah disebutkan, ada beberapa implementasi yang sangat mudah seperti Jetty yang memungkinkan Anda untuk menanamkan server web dalam aplikasi Anda yang berdiri sendiri sambil tetap mengambil keuntungan dari servlet api. Jika Anda benar-benar tidak dapat menggunakan Java EE API karena suatu alasan daripada harap abaikan komentar saya :-)
Chris Thompson
1
"Servlets" tidak benar-benar "Java EE". Mereka hanya cara menulis plugin yang dapat dipanggil oleh aplikasi di sekitarnya sebagai respons terhadap aktivitas pesan (hari ini, umumnya permintaan HTTP). Menyediakan lingkungan hosting servlet "hanya menggunakan Java SE API" persis seperti yang dilakukan Jetty dan Tomcat. Tentu saja Anda mungkin ingin membuang kerumitan yang tidak diinginkan tetapi kemudian Anda mungkin perlu memutuskan subset atribut yang diizinkan dan konfigurasi GET / POST. Meskipun sering tidak layak, kecuali untuk keamanan khusus / masalah tertanam.
David Tonhofer
1
Mungkin ada baiknya memeriksa daftar server http ini sebelum membuat keputusan. java-source.net/open-source/web-servers
ThreaT

Jawaban:

469

Sejak Java SE 6, ada server HTTP bawaan di Sun Oracle JRE. The com.sun.net.httpserverRingkasan paket menguraikan kelas terlibat dan berisi contoh-contoh.

Berikut ini adalah contoh kickoff yang di- copypasted dari dokumen mereka (untuk semua orang yang mencoba mengeditnya, karena ini adalah kode yang jelek, tolong jangan, ini adalah copy paste, bukan milikku, apalagi Anda tidak boleh mengedit kutipan kecuali mereka telah mengubah dalam sumber aslinya). Anda bisa menyalin 'n'paste'n'run di 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();
        }
    }

}

Perlu dicatat bahwa response.length()bagian dalam contoh mereka buruk, seharusnya response.getBytes().length. Bahkan kemudian, getBytes()metode harus secara eksplisit menentukan charset yang kemudian Anda tentukan di header respons. Sayangnya, meskipun sesat untuk pemula, itu semua hanya contoh awal kickoff.

Jalankan dan buka http: // localhost: 8000 / test dan Anda akan melihat respons berikut:

Inilah jawabannya


Untuk menggunakan com.sun.*kelas, perlu dicatat bahwa ini bertentangan dengan apa yang dipikirkan beberapa pengembang, sama sekali tidak dilarang oleh FAQ yang terkenal. Mengapa Pengembang Tidak Harus Menulis Program yang Menyebut Paket 'sun' . FAQ itu menyangkut sun.*paket (seperti sun.misc.BASE64Encoder) untuk penggunaan internal oleh Oracle JRE (yang dengan demikian akan mematikan aplikasi Anda ketika Anda menjalankannya di JRE yang berbeda), bukan com.sun.*paket. Sun / Oracle juga hanya mengembangkan perangkat lunak di atas Java SE API sendiri seperti setiap perusahaan lain seperti Apache dan sebagainya. Menggunakan com.sun.*kelas hanya dianjurkan (tetapi tidak dilarang) ketika menyangkut implementasi API Java tertentu, seperti GlassFish (Java EE impl), Mojarra (JSF impl), Jersey (JAX-RS impl), dll.

BalusC
sumber
19
@Waldheinz: seperti sebagai @Software Anda membingungkan sun.*dengan com.sun.*. Misalnya, apakah Anda melihat dokumentasi sun.*API? Lihat di sini: java.sun.com/products/jdk/faq/faq-sun-packages.html Apakah ada artinya com.sun.*? Itu com.sun.*hanya digunakan untuk perangkat lunak publik mereka sendiri yang bukan bagian dari Java API. Mereka juga mengembangkan perangkat lunak di atas Java API, seperti halnya setiap perusahaan lainnya.
BalusC
4
Saya pikir ini adalah server http yang sangat bagus untuk digunakan dalam kasus uji integrasi. terima kasih atas petunjuknya!
Andreas Petersson
13
Jika Anda menggunakan Eclipse dan mendapatkan kesalahan seperti "Pembatasan akses: Tipe HttpExchange tidak dapat diakses karena pembatasan pada perpustakaan yang diperlukan ...", stackoverflow.com/a/10642163 memberitahu cara menonaktifkan pemeriksaan akses itu.
Samuli Pahaoja
13
FWIW ini juga hadir di OpenJDK.
Jason C
6
Kelas-kelas yang dimaksud di sini ditandai @jdk.Exporteddalam kode sumber OpenJDK yang berarti bahwa API dianggap publik dan akan tersedia di Java 9 (beberapa com.sun.*paket lain akan menjadi tidak tersedia karena Project Jigsaw).
Jules
42

Lihat NanoHttpd

"NanoHTTPD adalah server HTTP ringan yang dirancang untuk disematkan dalam aplikasi lain, dirilis di bawah lisensi BSD yang Dimodifikasi.

Ini sedang dikembangkan di Github dan menggunakan Apache Maven untuk pengujian unit & pengembangan "

letronje
sumber
4
Satu peringatan: Kemungkinan NanoHTTPD tidak memiliki perlindungan terhadap serangan serangan pohon - Anda harus memeriksa ini jika akan melayani pada alamat publik. Maksud saya serangan di mana permintaan seperti GET /../../blahblah http/1.1dikeluarkan dan server berjalan di atas root situs web dan masuk ke lahan file sistem, melayani file yang dapat digunakan untuk kompromi atau menyerang sistem dari jarak jauh, seperti file password.
Lawrence Dol
7
Itu sepertinya diperbaiki. Versi saat ini menghasilkan 403 if (uri.startsWith ("..") || uri.endsWith ("..") || uri.indexOf ("../")> = 0).
Lena Schimmel
5
Saya tidak mengerti bagaimana ini merupakan jawaban untuk pertanyaan ini.
kimathie
28

The com.sun.net.httpserver solusi adalah tidak portabel di JRE. Lebih baik menggunakan API layanan web resmi di javax.xml.ws untuk mem -bootstrap server HTTP minimal ...

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: ini benar-benar berfungsi! Kode di atas terlihat seperti Groovy atau sesuatu. Berikut ini adalah terjemahan ke Jawa yang saya uji:

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
sumber
1
+1 untuk menjadi portabel. Sayang sekali Anda tidak dapat mengatur jenis konten respons apa adanya text/xml.
icza
1
Saya pikir Anda bisa melakukan <code> Server mengimplementasikan penyedia kelas <DataSource> {</code> ... dan kemudian menentukan Tipe-Konten dalam metode <code> getContentType () </code> DataSource. Selain itu Anda juga dapat menyuntikkan WebServiceContext: <code> @Resource WebServiceContext ctx; </code> untuk mengatur header lain dan membaca parameter permintaan. Sayangnya pengaturan tipe konten melalui WebServiceContext tidak berfungsi.
gruenewa
4
Bisakah Anda menjelaskan mengapa com.sun.net.HttpServer tidak portabel di JREs?
javabeangrinder
3
Tidak, kurasa tidak. Ini tidak akan berfungsi pada implementasi Java IBMs dan mungkin juga yang lain. Dan bahkan jika itu berfungsi sekarang, API internal diizinkan untuk berubah. Mengapa tidak menggunakan API resmi saja?
gruenewa
1
Tautan ini: docs.oracle.com/javase/9/docs/api/java.xml.ws-summary.html mengatakan bahwa modul java.xml.ws sudah tidak digunakan lagi sejak Java 9.
Erel Segal-Halevi
23

Saya suka pertanyaan ini karena ini adalah area di mana ada inovasi terus menerus dan selalu ada kebutuhan untuk memiliki server yang ringan terutama ketika berbicara tentang server yang tertanam dalam perangkat kecil (er). Saya pikir jawaban terbagi dalam dua kelompok besar.

  1. Thin-server : konten statis server-up dengan pemrosesan minimal, konteks atau pemrosesan sesi.
  2. Small-server : seolah-olah memiliki banyak kualitas server seperti httpD dengan jejak sekecil yang Anda bisa lolos.

Sementara saya mungkin mempertimbangkan perpustakaan HTTP seperti: Jetty , Apache Http Components , Netty dan lainnya lebih seperti fasilitas pemrosesan HTTP mentah. Pelabelan sangat subyektif, dan tergantung pada jenis hal yang Anda panggil untuk situs kecil. Saya membuat perbedaan ini dalam semangat pertanyaan, terutama komentar tentang ...

  • "... tanpa menulis kode untuk mem-parsing permintaan HTTP secara manual dan memformat respons HTTP secara manual ..."

Alat mentah ini memungkinkan Anda melakukan itu (seperti yang dijelaskan dalam jawaban lain). Mereka tidak benar-benar memberikan gaya siap pakai untuk membuat server yang ringan, tertanam atau mini. Mini-server adalah sesuatu yang dapat memberi Anda fungsionalitas yang mirip dengan server web yang berfungsi penuh (seperti katakanlah, Tomcat ) tanpa bel dan peluit, volume rendah, kinerja yang baik 99% dari waktu. Thin-server tampaknya lebih dekat dengan ungkapan asli hanya sedikit lebih banyak daripada mentah mungkin dengan fungsi subset terbatas, cukup untuk membuat Anda terlihat baik 90% dari waktu. Gagasan saya tentang mentah akan membuat saya terlihat bagus 75% - 89% dari waktu tanpa desain dan coding tambahan. Saya pikir jika / ketika Anda mencapai tingkat file WAR, kami telah meninggalkan "kecil" untuk server bonsi yang terlihat seperti semua server besar tidak lebih kecil.

Opsi server-tipis

Opsi mini-server:

  • Spark Java ... Hal-hal baik dimungkinkan dengan banyak konstruksi pembantu seperti Filter, Templat, dll.
  • MadVoc ... bertujuan untuk menjadi bonsai dan bisa juga ;-)

Di antara hal-hal lain yang perlu dipertimbangkan, saya akan menyertakan otentikasi, validasi, internasionalisasi, menggunakan sesuatu seperti FreeMaker atau alat template lain untuk membuat output halaman. Kalau tidak, mengelola pengeditan dan parameterisasi HTML kemungkinan akan membuat bekerja dengan HTTP terlihat seperti noughts-n-crosses. Secara alami itu semua tergantung pada seberapa fleksibel Anda perlu. Jika ini adalah mesin FAX yang digerakkan oleh menu, itu bisa sangat sederhana. Semakin banyak interaksi, semakin tebal kerangka kerja Anda. Pertanyaan bagus, semoga berhasil!

akan
sumber
21

Lihatlah server web "Jetty" Jetty . Sepotong perangkat lunak Open Source yang luar biasa yang tampaknya memenuhi semua persyaratan Anda.

Jika Anda bersikeras untuk menggulirkan sendiri maka lihatlah kelas "httpMessage".

James Anderson
sumber
Saya pikir api dermaga tergantung pada servlet.
dikembalikan
4
@Irreputable: Tidak, Jetty adalah server web yang sangat modular, yang memiliki wadah servlet sebagai salah satu modul opsionalnya.
Lawrence Dol
"Ada analog untuk fungsionalitas server" - ya itu API "servlet". Wadah servlet memanggil kelas Anda setelah menguraikan header, cookie, dll.
James Anderson
1
Sebagai catatan - Jetty hadir dengan implementasi API Servlet dan berfungsi baik dengan Java SE
James Anderson
4
Jetty terlalu besar dan memiliki banyak kurva pembelajaran sebelum penggunaan produksi aktual menjadi suatu kemungkinan.
ThreaT
18

Sekali waktu saya sedang mencari sesuatu yang serupa - server HTTP ringan namun berfungsi penuh yang saya dapat dengan mudah menanamkan dan menyesuaikan. Saya menemukan dua jenis solusi potensial:

  • Server lengkap yang tidak terlalu ringan atau sederhana (untuk definisi ekstrem ringan.)
  • Server yang benar-benar ringan yang tidak cukup server HTTP, tetapi contoh ServerSocket dimuliakan yang bahkan tidak sesuai dengan RFC dan tidak mendukung fungsi dasar yang umum dibutuhkan.

Jadi ... Saya mulai menulis JLHTTP - Java HTTP Server yang Ringan .

Anda dapat menanamkannya dalam proyek apa pun sebagai file sumber tunggal (jika agak panjang), atau sebagai stoples ~ 50K (~ 35K dilucuti) tanpa ketergantungan. Itu berusaha untuk menjadi RFC-compliant dan mencakup dokumentasi yang luas dan banyak fitur berguna sambil menjaga mengasapi ke minimum.

Fitur termasuk: host virtual, penyajian file dari disk, pemetaan tipe mime melalui file mime.types standar, pembuatan indeks direktori, file sambutan, dukungan untuk semua metode HTTP, ETag bersyarat dan dukungan header If- *, penyandian transfer chunked, gzip / deflate kompresi, HTTPS dasar (seperti yang disediakan oleh JVM), konten parsial (kelanjutan unduhan), penanganan multi-bagian / formulir-data untuk unggahan file, penangan konteks berganda melalui API atau anotasi, penguraian parameter (string kueri atau x-www-form-urlencoded) tubuh), dll.

Saya harap orang lain merasakan manfaatnya :-)

amichair
sumber
Metode utama adalah contoh yang baik dari penggunaan dasar, dan FAQ membahas banyak detail. Jika Anda memiliki saran untuk meningkatkan dokumen yang ada, jangan ragu untuk menghubungi saya secara langsung!
amichair
10

Spark adalah yang paling sederhana, berikut ini panduan mulai cepat: http://sparkjava.com/

Laercio Metzner
sumber
8

Dimungkinkan untuk membuat httpserver yang menyediakan dukungan dasar untuk servlet J2EE hanya dengan JDK dan api servlet hanya dalam beberapa baris kode.

Saya telah menemukan ini sangat berguna untuk servlets unit testing, karena mulai jauh lebih cepat daripada wadah ringan lainnya (kami menggunakan dermaga untuk produksi).

Httpserver yang paling ringan tidak memberikan dukungan untuk servlet, tetapi kami membutuhkannya, jadi saya pikir saya akan membagikannya.

Contoh di bawah ini memberikan dukungan servlet dasar, atau melempar dan UnsupportedOperationException untuk hal-hal yang belum diimplementasikan. Ia menggunakan com.sun.net.httpserver.HttpServer untuk dukungan http dasar.

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
sumber
Ini tidak memiliki beberapa metode pada ServletOutputStream dan ServletInputStream
BerandaAdhere Di manaThePcI
versi yang lebih baru dari servlet api, di atas cocok dengan 3.0 dan di bawah. Cukup tambahkan methdos yang hilang sesuai kebutuhan dalam contoh
f.carlsen
6

Saya sangat merekomendasikan melihat ke dalam Simple , terutama jika Anda tidak memerlukan kemampuan Servlet tetapi hanya akses ke objek permintaan / tanggapan. Jika Anda memerlukan REST, Anda dapat menempatkan Jersey di atasnya, jika Anda perlu menampilkan HTML atau yang serupa ada Freemarker. Saya benar-benar menyukai apa yang dapat Anda lakukan dengan kombinasi ini, dan ada relatif sedikit API untuk dipelajari.

Waldheinz
sumber
+1. Saya suka ide di balik Simple. Namun, masalah muncul ketika mencoba menggunakan HTTPS karena Mamba menghilangkan fitur "embeddable" dari Simple.
ThreaT
6

Kode ini lebih baik dari kita, Anda hanya perlu menambahkan 2 lib : javax.servelet.jar dan org.mortbay.jetty.jar .

Dermaga Kelas:

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

    }
} 

Kelas Servlet:

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
sumber
2
Pertanyaannya menanyakan solusi Java SE murni. Anda akan menemukan bahwa dermaga mengimplementasikan Java EE API.
Sridhar
Jetty berjalan dengan sangat baik menggunakan Java SE standar dan karenanya memenuhi persyaratan. Ini mengimplementasikan bagian dari Java EE API, itu tidak membutuhkannya . Ada perbedaan.
David Tonhofer
1
Ini tidak memenuhi syarat. + msgstr "hanya menggunakan Java SE API" .*.Servlet.jardan *.jetty.jarjelas bukan bagian dari Java SE.
icza
apakah saya perlu mengatur dermaga? atau bisakah saya singkirkan dua guci itu dan jalankan file ini?
Paul Preibisch
4

Semua jawaban di atas merinci tentang Handler Permintaan Utama berulir tunggal.

pengaturan:

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

Mengizinkan beberapa permintaan ditayangkan melalui beberapa utas menggunakan layanan pelaksana.

Jadi kode akhirnya akan seperti di bawah ini:

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();
        }
    }
}
Balu mallisetty
sumber
3

checkout Sederhana . ini adalah server embeddable yang cukup sederhana dengan dukungan bawaan untuk beragam operasi. Saya sangat suka model threading-nya ..

Luar biasa!

Olu Smith
sumber
2

Bagaimana dengan proyek Apache Commons HttpCore ?

Dari situs web: ... HttpCore Goals

  • Implementasi aspek transportasi HTTP yang paling mendasar
  • Seimbangkan antara kinerja yang baik dan kejelasan & ekspresi API
  • Jejak memori kecil (dapat diprediksi)
  • Pustaka mandiri (tidak ada dependensi eksternal di luar JRE)
Iqbal
sumber
Itu mungkin level terlalu rendah. Setidaknya seseorang harus mencari solusi yang memanggil kode Anda di tingkat servlet API, kecuali jika seseorang ingin berurusan dengan semua konsep seperti chunking, encoding dll. Itu bisa menyenangkan.
David Tonhofer
2

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

API ini telah membuat server HTTP menggunakan soket.

  1. Itu mendapat permintaan dari browser sebagai teks
  2. Parsing untuk mengambil info URL, metode, atribut, dll.
  3. Membuat respons dinamis menggunakan pemetaan URL yang ditentukan
  4. Mengirim respons ke browser.

Sebagai contoh, inilah cara konstruktor di Response.javakelas mengubah respons mentah menjadi respons 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;
}
Devashish Priyadarshi
sumber
1

Anda dapat menulis server Jetty Java tertanam yang cukup sederhana .

Embedded Jetty berarti bahwa server (Jetty) dikirimkan bersama dengan aplikasi sebagai lawan dari penerapan aplikasi pada server Jetty eksternal.

Jadi jika dalam pendekatan non-embedded webapp Anda dibangun ke dalam file WAR yang digunakan untuk beberapa server eksternal ( Tomcat / Jetty / etc), di Jetty tertanam, Anda menulis webapp dan instantiate server dermaga di basis kode yang sama.

Contoh untuk server Jetty Java tertanam, Anda dapat menggunakan clone dan menggunakan: https://github.com/stas-slu/embedded-jetty-java-server-example

Johnny
sumber