Отправка и получение двоичных данных в сервлетах - PullRequest
9 голосов
/ 03 марта 2011

Я пытаюсь написать сервлет Java для получения запросов двоичных данных и ответа на них, используя HttpServletRequest.getOutputStream() и HttpServletResponse.getInputStream().Это для проекта, который включает в себя отправку запроса клиентом Silverlight, на который этот сервлет отвечает через соединение HTTP POST.В настоящее время для тестирования сервлета я реализую клиент на Java, с которым я более знаком, чем Silverlight.

Проблема заключается в том, что в моем тестовом проекте я отправляю данные из клиента сервлета в видемассив байтов и ожидаю получить массив байтов той же длины - только это не так, и вместо этого я получаю один байт.Поэтому я публикую здесь соответствующие фрагменты кода в надежде, что вы укажете мне, где я делаю ошибку, и, надеюсь, предоставлю соответствующую библиографию, чтобы помочь мне в дальнейшем.

Итак, пошли.

клиент сервлет обрабатывает запросы POST с очень простой HTML-страницы с формой, которую я использую в качестве внешнего интерфейса.Я не слишком беспокоюсь об использовании JSP и т. Д., Вместо этого я сосредоточен на том, чтобы заставить меж сервлетную связь работать .

<code>// client HttpServlet invokes this method from doPost(request,response)
private void process(HttpServletRequest request, HttpServletResponse response) 
throws ServletException, IOException {
  String firstName = (String) request.getParameter("firstname");
  String lastName = (String) request.getParameter("lastname");
  String xmlRequest = "<MyRequest><Person><Name Firstname=\""+firstName+"\" Lastname=\""+lastName+"\" /></Person></MyRequest>";

  OutputStream writer = null;
  InputStream reader = null;
  try {
    URL url = new URL("http://localhost:8080/project/Server");
    URLConnection conn = url.openConnection();
    conn.setDoInput(true);
    conn.setDoOutput(true);

    writer = conn.getOutputStream();
    byte[] baXml = xmlRequest.getBytes("UTF-8");
    writer.write(baXml, 0,baXml.length);
    writer.flush();
    // perhaps I should be waiting here? how?

    reader = conn.getInputStream();
    int available = reader.available();
    byte[] data = new byte[available];
    reader.read(data,0,available);
    String xmlResponse = new String(data,"UTF-8");

    PrintWriter print = response.getWriter();
    print.write("<html><body>Response:<br/><pre>");
    print.write(xmlResponse);
    print.write("
"); print.close ();} наконец {if (writer! = null) writer.close (); if (reader! = null) reader.close ();}}

Сервер Сервлет обрабатывает HTTP-запросы POST. Это делается путем получения запросов от клиентского сервлета для тестирования, но в будущем я собираюсь использовать его для клиентов на других языках (в частности, Silverlight).

// server HttpServlet invokes this method from doPost(request,response)
private void process(HttpServletRequest request, HttpServetResponse response)
throws ServletException, IOException {
  ServletInputStream sis = null;
  try {
    sis = request.getInputStream();
    // maybe I should be using a BufferedInputStream 
    // instead of the InputStream directly?
    int available = sis.available();
    byte[] input = new byte[available];
    int readBytes = sis.read(input,0,available);
    if(readBytes!=available) {
      throw new ServletException("Oops! readBytes!=availableBytes");
    }

    // I ONLY GET 1 BYTE OF DATA !!! 
    // It's the first byte of the client message, a '<'.
    String msg = "Read "+readBytes+" bytes of "
                 +available+" available from request InputStream.";
    System.err.println("Server.process(HttpServletRequest,HttpServletResponse): "+msg);
    String xmlReply = "<Reply><Message>"+msg+"</Message></Reply>";
    byte[] data = xmlReply.getBytes("UTF-8");
    ServletOutputStream sos = response.getOutputStream();
    sos.write(data, 0,data.length);
    sos.flush();
    sos.close();

  } finally {
    if(sis!=null)
      sis.close();
  }
}

Я до сих пор придерживался байтовых массивов вместо использования BufferInputStream s, потому что я еще не решил, буду ли я использовать, например, строки в кодировке Base64 для передачи данных или я буду отправлять двоичные данные как ...есть.

Заранее спасибо.

Ответы [ 2 ]

8 голосов
/ 14 декабря 2011

Для копирования входного потока в выходной поток используйте стандартный способ:

InputStream is=request.getInputStream();
OutputStream os=response.getOutputStream();
byte[] buf = new byte[1000];
for (int nChunk = is.read(buf); nChunk!=-1; nChunk = is.read(buf))
{
    os.write(buf, 0, nChunk);
} 
3 голосов
/ 03 марта 2011

Единственное, о чем я могу думать, это то, что вы читаете только request.getInputStream().available() байт, а затем решаете, что у вас есть все.Согласно документации , available() вернет количество байтов, которые могут быть прочитаны без блокировки, но я не вижу никаких упоминаний о том, действительно ли это гарантировано будет всем содержимым входного потока, поэтому склонен предположить, что такие гарантии не предоставляются.

Я не уверен, как лучше узнать, когда больше нет данных (может быть, Content-Length в запросе может помочь?), не рискуя блокироватьнеопределенно в EOF, но я бы попытался зацикливаться, пока не прочитал все данные из входного потока.Чтобы проверить эту теорию, вы всегда можете отсканировать входные данные для поиска известного шаблона, который встречается дальше в потоке, возможно, >, совпадающего с исходным <, который вы получаете.

...