【问题标题】:Jetty: inputstream in Handler always empty. how to get an input stream from clientJetty:处理程序中的输入流始终为空。如何从客户端获取输入流
【发布时间】:2020-07-09 20:23:15
【问题描述】:

我想基于jetty 9.4.27开发一个ntrip caster。 http-client 通过 http-POST 发送数据。

程序(ntrip协议)必须如下:

  1. 客户端:发送“POST /Mount-Point HTTP/1.1”
  2. 服务器:发送状态码 200 作为确认(HTTP/1.1 200 OK)
  3. 客户端:等到收到状态码 200
  4. 客户端:开始连续发送数据

重要提示:整个事情必须在一个请求中运行

第 1 步和第 2 步有效: Jetty-handler 的调用工作正常。 客户端收到状态码 200 并开始数据传输。 虽然客户端写入输出流,但数据并没有到达服务器。

baseRequest.getReader() 和 request.getReader() 始终为“空”。

我的代码有什么问题? 带有简单套接字的服务器实现可以很好地与此客户端程序配合使用。 Jetty 有类似的可能吗?

客户端是用一个简单的套接字实现的。 简化后的代码如下...

// create Socket to connect jetty server
InetAddress addr = InetAddress.getByName(host);
socket = new Socket(addr, port);
...
bufferedWriter = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(), "UTF8"));
bufferedWriter.write(createHttpPost())  // Send POST /Mount-Point HTTP/1.1 ...
...
if (checkResponseCode200(response.toString())){
   // Status Code 200 received. send data continuously
   while(true){
      socket.getOutputStream().write(Utils.convertByteToByteArray(msg));
      socket.getOutputStream().flush();
   }
}       
/*
*  Jetty Programmcode
*/
package ch.dca.caster;

import org.apache.http.util.ByteArrayBuffer;
import org.eclipse.jetty.server.*;
import org.eclipse.jetty.server.handler.AbstractHandler;
import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.server.handler.HandlerCollection;
import org.eclipse.jetty.util.thread.QueuedThreadPool;

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

public class JettyServer {
    private Server server;

    public void start() throws Exception {
        server = new Server(new QueuedThreadPool(128, 8));
        ServerConnector connector = new ServerConnector(server);
        connector.setPort(1083);
        server.setConnectors(new Connector[]{connector});
        server.setHandler(new InitialHandler());
        server.start();
    }

   public class InitialHandler extends AbstractHandler {
        @Override
        public void handle(String target,
                           Request baseRequest,
                           HttpServletRequest request,
                           HttpServletResponse response) throws IOException,ServletException

        {
           // printout Request-Header

           System.out.println("**** Before request.getReader() :  baseRequest = " + baseRequest);
           System.out.println("**** Header");
           Enumeration<String> headerValues = baseRequest.getHeaderNames();
           List<String> headerValuesList= Collections.list(headerValues);

           for(String s:headerValuesList){
                System.out.println(s + ": " + baseRequest.getHeader(s));
           }
           /* Result ....
               **** Before request.getReader() :  baseRequest = Request(POST //192.168.1.112/CHE8304A)@7698d57b
               **** Header
               Host: 192.168.1.112
               Authorization: Basic ZGNhcnRjbTpZaUpiYks4Ug==
               Ntrip-Version: Ntrip/2.0
               Content-Type: gnss/data
               User-Agent: NTRIP dca.telemetry.server
               Connection: close
           */

            //
            // Step 1: 
            // compliant to ntrip protocol:  first of all send status code 200 to the client
            //
            response.setContentType("text/plain; charset=utf-8");
            response.setStatus(HttpServletResponse.SC_OK);
            PrintWriter out = response.getWriter();
            out.println("OK");
            out.flush();

            //
            // Step 2: 
            // Client starts streaming the data as soon as code 200 is received
            // client: --> socket.getOutputStream().write(Utils.convertByteToByteArray(msg));
            //

            BufferedReader is = request.getReader(); // <----- not working: allways Empty !!!
            boolean doRead = true;
            while (doRead){
                int c = is.read();
                while (c > -1) {
                    System.out.print(int2Byte(c));
                    c = is.read();
                }

            }
            baseRequest.setHandled(true);
        }
    }
}

【问题讨论】:

  • 在调用request.getReader() 之前添加System.out.println("baseRequest = " + baseRequest); 并再次运行它。然后请使用详细信息编辑/更新此问题。 (应该产生多行输出,请包括它们)
  • 你好,我做了以下 ..System.out.println("**** Before request.getReader() : baseRequest = " + baseRequest); BufferedReader is = request.getReader(); // &lt;----- not working: allways Empty !!! 结果只有一行:**** Before request.getReader() : baseRequest = Request(POST //192.168.1.112/CHE8304A)@7698d57b
  • 应该转储请求详细信息(请求行和标头),您真的没有针对该请求发送标头吗?
  • 使用baseRequest.getHeader() ,标题条目如下所示:POST //192.168.1.112/CHE8304A [\n]Authorization: Basic ZGNhcnRjbTpZaUpiYks4Ug== [\n]User-Agent: NTRIP pac.telemetry.server [\n]Connection: close [\n]@ 987654332@ [\n]Ntrip-Version: Ntrip/2.0 [\n]Content-Type: gnss/data
  • 请编辑您的问题并包含详细信息,cmets 部分不适合介绍技术细节。

标签: jetty


【解决方案1】:

您指定的请求标头:

Host: 192.168.1.112
Authorization: Basic ZGNhcnRjbTpZaUpiYks4Ug==
Ntrip-Version: Ntrip/2.0
Content-Type: gnss/data
User-Agent: NTRIP dca.telemetry.server
Connection: close

这组标题中没有明显的正文内容。

通常有 3 种方法可以通过 HTTP 请求发送正文内容...

  1. 带有一个Content-Length 标头指示正文的长度。 (支持 HTTP/1.0、HTTP/1.1 甚至 HTTP/2)
  2. 带有一个 Transfer-Encoding: chunked 标头,指示未确定的正文内容长度(仅在 HTTP/1.1 上支持,并且需要特定的编码格式才能正常工作。RFC7230: Section 4.1
  3. 连接关闭之前的原始正文内容。 (老式 HTTP/1.0 技术)

我建议使用技术 #1 或 #2 以最大限度地与规范兼容并减少与 HTTP 中介(代理、负载平衡器、缓存服务器等)的复杂性

另外需要注意的是HTTP方法(GET、POST、PUT等)。 并非所有方法都支持正文内容。 (所以坚持你所指出的 POST 以消除这种并发症)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-05-30
    • 1970-01-01
    • 2021-03-22
    • 1970-01-01
    • 2012-02-23
    • 2018-08-07
    • 1970-01-01
    相关资源
    最近更新 更多