2015-10-27 6 views
4

Я работаю над приложением Java, который имеет встроенный HTTP-сервер, на данный момент сервер реализован с использованием ServerSocketChannel, он прослушивает порт 1694 для запросов:сервера HTTP Java отсылки фрагментированный ответа

 msvrCh = ServerSocketChannel.open(); 
     msvrCh.socket().bind(new InetSocketAddress(mintPort)); 
     msvrCh.configureBlocking(false); 

нить устанавливается для управления запросами и ответами:

 Thread thrd = new Thread(msgReceiver); 
     thrd.setUncaughtExceptionHandler(exceptionHandler); 
     thrd.start(); 

нить довольно прост:

 Runnable msgReceiver = new Runnable() { 
      @Override 
      public void run() { 
       try{ 
        while(!Thread.interrupted()) { 
    //Sleep a short period between checks for new requests       
         try{ 
          Thread.sleep(DELAY_BETWEEN_ACCEPTS); 
         } catch(Exception ex) { 
          ex.printStackTrace(); 
         }       
         SocketChannel cliCh = msvrCh.accept(); 

         if (blnExit() == true) { 
          break; 
         }       
         if (cliCh == null) { 
          continue; 
         } 
         processRequest(cliCh.socket()); 
        }      
       } catch (IOException ex) { 
        ex.printStackTrace(); 
       } finally {      
        logMsg(TERMINATING_THREAD + 
          "for accepting cluster connections", true); 

        if (msvrCh != null) { 
         try { 
          msvrCh.close(); 
         } catch (IOException ex) { 
          ex.printStackTrace(); 
         } 
         msvrCh = null; 
        } 
       }    
      } 
     }; 

Основная часть коды для работы с ответом в функции ProcessRequest:

private void processRequest(Socket sck) { 
    try { 
    //AJAX Parameters 
     final String AJAX_ID   = "ajmid"; 
    //The 'Handler Key' used to decode response   
     final String HANDLER_KEY  = "hkey"; 
    //Message payload   
     final String PAYLOAD   = "payload"; 
    //Post input buffer size    
     final int REQUEST_BUFFER_SIZE = 4096; 
    //Double carriage return marks the end of the headers   
     final String CRLF    = "\r\n"; 

     BufferedReader in = new BufferedReader(new InputStreamReader(sck.getInputStream())); 
     String strAMID = null, strHKey = null, strRequest; 
     char[] chrBuffer = new char[REQUEST_BUFFER_SIZE]; 
     StringBuffer sbRequest = new StringBuffer(); 
     eMsgTypes eType = eMsgTypes.UNKNOWN; 
     clsHTTPparameters objParams = null; 
     int intPos, intCount;    
    //Extract the entire request, including headers   
     if ((intCount = in.read(chrBuffer)) == 0) { 
      throw new Exception("Cannot read request!"); 
     } 
     sbRequest.append(chrBuffer, 0, intCount);   
     strRequest = sbRequest.toString(); 
    //What method is being used by this request? 
     if (strRequest.startsWith(HTTP_GET)) { 
    //The request should end with a HTTP marker, remove this before trying to interpret the data 
      if (strRequest.indexOf(HTTP_MARKER) != -1) { 
       strRequest = strRequest.substring(0, strRequest.indexOf(HTTP_MARKER)).trim(); 
      }    
    //Look for a data marker 
      if ((intPos = strRequest.indexOf(HTTP_DATA_START)) >= 0) { 
    //Data is present in the query, skip to the start of the data 
       strRequest = strRequest.substring(intPos + 1); 
      } else { 
    //Remove the method indicator 
       strRequest = strRequest.substring(HTTP_GET.length());     
      } 
     } else if (strRequest.startsWith(HTTP_POST)) { 
    //Discard the headers and jump to the data 
      if ((intPos = strRequest.lastIndexOf(CRLF)) >= 0) { 
       strRequest = strRequest.substring(intPos + CRLF.length()); 
      } 
     } 
     if (strRequest.length() > 1) { 
    //Extract the parameters      
      objParams = new clsHTTPparameters(strRequest); 
     }    
     if (strRequest.startsWith("/") == true) { 
    //Look for the document reference 
      strRequest = strRequest.substring(1);    
      eType = eMsgTypes.SEND_DOC;    
     } 
     if (objParams != null) { 
    //Transfer the payload to the request 
      String strPayload = objParams.getValue(PAYLOAD); 

      if (strPayload != null) { 
       byte[] arybytPayload = Base64.decodeBase64(strPayload.getBytes()); 
       strRequest = new String(arybytPayload); 
       strAMID = objParams.getValue(AJAX_ID); 
       strHKey = objParams.getValue(HANDLER_KEY); 
      } 
     } 
     if (eType == eMsgTypes.UNKNOWN 
      && strRequest.startsWith("{") && strRequest.endsWith("}")) { 
    //The payload is JSON, is there a type parameter? 
      String strType = strGetJSONItem(strRequest, JSON_LBL_TYPE); 

      if (strType != null && strType.length() > 0) { 
    //Decode the type     
       eType = eMsgTypes.valueOf(strType.toUpperCase().trim()); 
    //What system is the message from? 
       String strIP = strGetJSONItem(strRequest, JSON_LBL_IP) 
         ,strMAC = strGetJSONItem(strRequest, JSON_LBL_MAC);     
       if (strIP != null && strIP.length() > 0 
       && strMAC != null && strMAC.length() > 0) { 
    //Is this system known in the cluster? 
        clsIPmon objSystem = objAddSysToCluster(strIP, strMAC); 

        if (objSystem != null) { 
    //Update the date/time stamp of the remote system       
         objSystem.touch();       
        } 
    //This is an internal cluster message, no response required 
        return; 
       }     
      } 
     }    
     String strContentType = null, strRespPayload = null; 
     OutputStream out = sck.getOutputStream(); 
     byte[] arybytResponse = null; 
     boolean blnShutdown = false; 
     out.write("HTTP/1.0 200\n".getBytes()); 

     switch(eType) { 
     case SEND_DOC: 
      if (strRequest.length() <= 1) { 
       strRequest = HTML_ROOT + DEFAULT_DOC; 
      } else { 
       strRequest = HTML_ROOT + strRequest; 
      } 
      logMsg("HTTP Request for: " + strRequest, true); 

      if (strRequest.toLowerCase().endsWith(".css") == true) { 
       strContentType = MIME_CSS; 
      } else if (strRequest.toLowerCase().endsWith(".gif") == true) { 
       strContentType = MIME_GIF; 
      } else if (strRequest.toLowerCase().endsWith(".jpg") == true) { 
       strContentType = MIME_JPG; 
      } else if (strRequest.toLowerCase().endsWith(".js") == true) { 
       strContentType = MIME_JS; 
      } else if (strRequest.toLowerCase().endsWith(".png") == true) { 
       strContentType = MIME_PNG; 
      } else if (strRequest.toLowerCase().endsWith(".html") == true 
        || strRequest.toLowerCase().endsWith(".htm") == true) { 
       strContentType = MIME_HTML; 
      } 
      File objFile = new File(strRequest); 

      if (objFile.exists() == true) { 
       FileInputStream objFIS = new FileInputStream(objFile); 

       if (objFIS != null) { 
        arybytResponse = new byte[(int)objFile.length()]; 

        if (objFIS.read(arybytResponse) == 0) { 
         arybytResponse = null; 
        } 
        objFIS.close(); 
       } 
      } 
      break; 
     case CHANNEL_STS: 
      strRespPayload = strChannelStatus(strRequest); 
      strContentType = MIME_JSON; 
      break; 
     case CLUSTER_STS: 
      strRespPayload = strClusterStatus(); 
      strContentType = MIME_JSON; 
      break; 
     case MODULE_STS: 
      strRespPayload = strModuleStatus(strRequest); 
      strContentType = MIME_JSON; 
      break; 
     case NETWORK_INF: 
      strRespPayload = strNetworkInfo(strRequest); 
      strContentType = MIME_JSON; 
      break; 
     case NODE_STS: 
      strRespPayload = strNodeStatus(strRequest); 
      strContentType = MIME_JSON; 
      break; 
     case POLL_STS: 
      strRespPayload = strPollStatus(strRequest); 
      strContentType = MIME_JSON; 
      break; 
     case SYS_STS: 
    //Issue system status    
      strRespPayload = strAppStatus(); 
      strContentType = MIME_JSON; 
      break;   
     case SHUTDOWN: 
    //Issue instruction to restart system 
      strRespPayload = "Shutdown in progress!"; 
      strContentType = MIME_PLAIN; 
    //Flag that shutdown has been requested    
      blnShutdown = true; 
      break; 
     default: 
     } 
     if (strRespPayload != null) { 
    //Convert response string to byte array    
      arybytResponse = strRespPayload.getBytes(); 
    System.out.println("[ " + strRespPayload.length() + " ]: " + strRespPayload);   //HACK   
     }   
     if (arybytResponse != null && arybytResponse.length > 0) { 
      if (strContentType == MIME_JSON) { 
       String strResponse = "{"; 

       if (strAMID != null) { 
    //Include the request AJAX Message ID in the response 
        if (strResponse.length() > 1) { 
         strResponse += ","; 
        } 
        strResponse += "\"" + AJAX_ID + "\":" + strAMID; 
       } 
       if (strHKey != null) { 
        if (strResponse.length() > 1) { 
         strResponse += ","; 
        } 
        strResponse += "\"" + HANDLER_KEY + "\":\"" + strHKey + "\""; 
       } 
       if (strResponse.length() > 1) { 
        strResponse += ","; 
       } 
       strResponse += "\"payload\":" + new String(arybytResponse) 
          + "}";     
       arybytResponse = strResponse.getBytes(); 
      } 
      String strHeaders = ""; 

      if (strContentType != null) { 
       strHeaders += "Content-type: " + strContentType + "\n";     
      } 
      strHeaders += "Content-length: " + arybytResponse.length + "\n" 
         + "Access-Control-Allow-Origin: *\n" 
         + "Access-Control-Allow-Methods: POST, GET, OPTIONS, DELETE, PUT\n" 
         + "Access-Control-Allow-Credentials: true\n" 
         + "Keep-Alive: timeout=2, max=100\n" 
         + "Cache-Control: no-cache\n" 
         + "Pragma: no-cache\n\n"; 
      out.write(strHeaders.getBytes()); 
      out.write(arybytResponse); 
      out.flush();     
     } 
     out.close(); 
     sck.close(); 

     if (blnShutdown == true) { 
      String strSystem = mobjLocalIP.strGetIP(); 

      if (strSystem.compareTo(mobjLocalIP.strGetIP()) != 0) { 
    //Specified system is not the local system, issue message to remote system. 
       broadcastMessage("{\"" + JSON_LBL_TYPE + "\":\"" + 
                eMsgTypes.SHUTDOWN + "\"" 
           + ",\"" + JSON_LBL_TIME + "\":\"" + 
              clsTimeMan.lngTimeNow() + "\"}");        
      } else { 
    //Shutdown addressed to local system      
       if (getOS().indexOf("linux") >= 0) { 
    //TO DO!!!     
       } else if (getOS().indexOf("win") >= 0) { 
        Runtime runtime = Runtime.getRuntime(); 
        runtime.exec("shutdown /r /c \"Shutdown request\" /t 0 /f"); 
        System.exit(EXITCODE_REQUESTED_SHUTDOWN); 
       }    
      } 
     } 
    } catch (Exception ex) {    
    } finally { 
     if (sck != null) { 
      try { 
       sck.close(); 
      } catch (IOException ex) { 
       ex.printStackTrace(); 
      } 
     } 
    } 
} 

Я хотел бы реализовал фрагментированный ответ, в настоящее время фрагментированных ответы не поддерживаются кодом выше.

[Редактировать] Я пытался реализовать Chunked реакцию путем добавления метода:

/** 
    * @param strData - The data to split into chunks 
    * @return A string array containing the chunks 
    */ 
public static String[] arystrChunkData(String strData) { 
    int intChunks = (strData.length()/CHUNK_THRESHOLD_BYTESIZE) + 1; 
    String[] arystrChunks = new String[intChunks]; 
    int intLength = strData.length(), intPos = 0; 

    for(int c=0; c<arystrChunks.length; c++) {    
     if (intPos < intLength) { 
    //Extract a chunk from the data   
      int intEnd = Math.min(intLength - 1, intPos + CHUNK_THRESHOLD_BYTESIZE); 
      arystrChunks[c] = strData.substring(intPos, intEnd); 
     } 
    //Advance data position to next chunk   
     intPos += CHUNK_THRESHOLD_BYTESIZE; 
    }  
    return arystrChunks; 
} 

Модифицированный ProcessRequest теперь выглядит следующим образом:

 private void processRequest(Socket sck) { 
    try { 
     //AJAX Parameters 
     final String AJAX_ID   = "ajmid"; 
     //The 'Handler Key' used to decode response   
     final String HANDLER_KEY  = "hkey"; 
     //Message payload   
     final String PAYLOAD   = "payload"; 
     //Post input buffer size    
     final int REQUEST_BUFFER_SIZE = 4096; 
     //Double carriage return marks the end of the headers   
     final String CRLF    = "\r\n"; 

     BufferedReader in = new BufferedReader(new InputStreamReader(sck.getInputStream())); 
     String strAMID = null, strHKey = null, strRequest; 
     char[] chrBuffer = new char[REQUEST_BUFFER_SIZE]; 
     StringBuffer sbRequest = new StringBuffer(); 
     eMsgTypes eType = eMsgTypes.UNKNOWN; 
     clsHTTPparameters objParams = null; 
     int intPos, intCount;    
     //Extract the entire request, including headers   
     if ((intCount = in.read(chrBuffer)) == 0) { 
      throw new Exception("Cannot read request!"); 
     } 
     sbRequest.append(chrBuffer, 0, intCount);   
     strRequest = sbRequest.toString(); 
     //What method is being used by this request? 
     if (strRequest.startsWith(HTTP_GET)) { 
     //The request should end with a HTTP marker, remove this before trying to interpret the data 
      if (strRequest.indexOf(HTTP_MARKER) != -1) { 
       strRequest = strRequest.substring(0, strRequest.indexOf(HTTP_MARKER)).trim(); 
      }    
     //Look for a data marker 
      if ((intPos = strRequest.indexOf(HTTP_DATA_START)) >= 0) { 
     //Data is present in the query, skip to the start of the data 
       strRequest = strRequest.substring(intPos + 1); 
      } else { 
     //Remove the method indicator 
       strRequest = strRequest.substring(HTTP_GET.length());     
      } 
     } else if (strRequest.startsWith(HTTP_POST)) { 
     //Discard the headers and jump to the data 
      if ((intPos = strRequest.lastIndexOf(CRLF)) >= 0) { 
       strRequest = strRequest.substring(intPos + CRLF.length()); 
      } 
     } 
     if (strRequest.length() > 1) { 
     //Extract the parameters      
      objParams = new clsHTTPparameters(strRequest); 
     }    
     if (strRequest.startsWith("/") == true) { 
     //Look for the document reference 
      strRequest = strRequest.substring(1);    
      eType = eMsgTypes.SEND_DOC;    
     } 
     if (objParams != null) { 
     //Transfer the payload to the request 
      String strPayload = objParams.getValue(PAYLOAD); 

      if (strPayload != null) { 
       byte[] arybytPayload = Base64.decodeBase64(strPayload.getBytes()); 
       strRequest = new String(arybytPayload); 
       strAMID = objParams.getValue(AJAX_ID); 
       strHKey = objParams.getValue(HANDLER_KEY); 
      } 
     } 
     if (eType == eMsgTypes.UNKNOWN 
      && strRequest.startsWith("{") && strRequest.endsWith("}")) { 
     //The payload is JSON, is there a type parameter? 
      String strType = strGetJSONItem(strRequest, JSON_LBL_TYPE); 

       if (strType != null && strType.length() > 0) { 
     //Decode the type     
       eType = eMsgTypes.valueOf(strType.toUpperCase().trim()); 
     //What system is the message from? 
       String strIP = strGetJSONItem(strRequest, JSON_LBL_IP) 
         ,strMAC = strGetJSONItem(strRequest, JSON_LBL_MAC);     
       if (strIP != null && strIP.length() > 0 
       && strMAC != null && strMAC.length() > 0) { 
     //Is this system known in the cluster? 
        clsIPmon objSystem = objAddSysToCluster(strIP, strMAC); 

        if (objSystem != null) { 
     //Update the date/time stamp of the remote system       
         objSystem.touch();       
        } 
     //This is an internal cluster message, no response required 
        return; 
       }     
      } 
     }    
     String strContentType = null, strRespPayload = null;    
     OutputStream out = sck.getOutputStream(); 
     byte[] arybytResponse = null; 
     boolean blnShutdown = false; 
     //Start the writing the headers 
     String strHeaders = "HTTP/1.0 200\n" 
          + "Date: " + (new Date()).toString() + "\n" 
          + "Access-Control-Allow-Origin: *\n" 
          + "Access-Control-Allow-Methods: POST, GET, OPTIONS, DELETE, PUT\n" 
          + "Access-Control-Allow-Credentials: true\n" 
          + "Keep-Alive: timeout=2, max=100\n" 
          + "Cache-Control: no-cache\n" 
          + "Pragma: no-cache\n";    
     out.write(strHeaders.getBytes()); 
     strHeaders = ""; 

     switch(eType) { 
     case SEND_DOC: 
      if (strRequest.length() <= 1) { 
       strRequest = HTML_ROOT + DEFAULT_DOC; 
      } else { 
       strRequest = HTML_ROOT + strRequest; 
      } 
      logMsg("HTTP Request for: " + strRequest, true); 

      if (strRequest.toLowerCase().endsWith(".css") == true) { 
       strContentType = MIME_CSS; 
      } else if (strRequest.toLowerCase().endsWith(".gif") == true) { 
       strContentType = MIME_GIF; 
      } else if (strRequest.toLowerCase().endsWith(".jpg") == true) { 
       strContentType = MIME_JPG; 
      } else if (strRequest.toLowerCase().endsWith(".js") == true) { 
       strContentType = MIME_JS; 
      } else if (strRequest.toLowerCase().endsWith(".png") == true) { 
       strContentType = MIME_PNG; 
      } else if (strRequest.toLowerCase().endsWith(".html") == true 
        || strRequest.toLowerCase().endsWith(".htm") == true) { 
       strContentType = MIME_HTML; 
      } 
      File objFile = new File(strRequest); 

      if (objFile.exists() == true) { 
       FileInputStream objFIS = new FileInputStream(objFile); 

       if (objFIS != null) { 
        arybytResponse = new byte[(int)objFile.length()]; 

        if (objFIS.read(arybytResponse) == 0) { 
         arybytResponse = null; 
        } 
        objFIS.close(); 
       } 
      } 
      break; 
     case CHANNEL_STS: 
      strRespPayload = strChannelStatus(strRequest); 
      strContentType = MIME_JSON; 
      break; 
     case CLUSTER_STS: 
      strRespPayload = strClusterStatus(); 
      strContentType = MIME_JSON; 
      break; 
     case MODULE_STS: 
      strRespPayload = strModuleStatus(strRequest); 
      strContentType = MIME_JSON; 
      break; 
     case NETWORK_INF: 
      strRespPayload = strNetworkInfo(strRequest); 
      strContentType = MIME_JSON; 
      break; 
     case NODE_STS: 
      strRespPayload = strNodeStatus(strRequest); 
      strContentType = MIME_JSON; 
      break; 
     case POLL_STS: 
      strRespPayload = strPollStatus(strRequest); 
      strContentType = MIME_JSON; 
      break; 
     case SYS_STS: 
     //Issue system status    
      strRespPayload = strAppStatus(); 
      strContentType = MIME_JSON; 
      break;   
     case SHUTDOWN: 
     //Issue instruction to restart system 
      strRespPayload = "Shutdown in progress!"; 
      strContentType = MIME_PLAIN; 
     //Flag that shutdown has been requested    
      blnShutdown = true; 
      break; 
     default: 
     } 
     if (strRespPayload != null) { 
     //Convert response string to byte array    
      arybytResponse = strRespPayload.getBytes(); 
     }   
     if (arybytResponse != null && arybytResponse.length > 0) { 
      boolean blnChunked = false; 

      if (strContentType != null) { 
       strHeaders += "Content-type: " + strContentType + "\n";     
      }    
      if (strContentType == MIME_JSON) { 
       String strResponse = "{"; 

       if (strAMID != null) { 
     //Include the request AJAX Message ID in the response 
        if (strResponse.length() > 1) { 
         strResponse += ","; 
        } 
        strResponse += "\"" + AJAX_ID + "\":" + strAMID; 
       } 
       if (strHKey != null) { 
        if (strResponse.length() > 1) { 
         strResponse += ","; 
        } 
        strResponse += "\"" + HANDLER_KEY + "\":\"" + strHKey + "\""; 
       } 
       if (strResponse.length() > 1) { 
        strResponse += ","; 
       } 
       strResponse += "\"payload\":" + new String(arybytResponse) 
          + "}"; 
     //How big is the response? 
    if (strResponse.length() > CHUNK_THRESHOLD_BYTESIZE) { 
        blnChunked = true; 
        strHeaders += "Transfer-Encoding: chunked\n\n"; 
        out.write(strHeaders.getBytes()); 
     //Slice up the string into chunks 
          String[] arystrChunks = arystrChunkData(strResponse); 

        for(int c=0; c<arystrChunks.length; c++) { 
         String strChunk = arystrChunks[c]; 

         if (strChunk != null) { 
          String strLength = Integer.toHexString(strChunk.length()) + "\r\n"; 
          strChunk += "\r\n"; 
          out.write(strLength.getBytes()); 
          out.write(strChunk.getBytes()); 
         }       
        } 
     //Last chunk is always 0 bytes      
        out.write("0\r\n\r\n".getBytes()); 
       } else { 
        arybytResponse = strResponse.getBytes(); 
       } 
      } 
      if (blnChunked == false) {  
       strHeaders += "Content-length: " + arybytResponse.length + "\n\n";       
       out.write(strHeaders.getBytes()); 
       out.write(arybytResponse); 
      } 
      out.flush();     
     } 
     out.close(); 
     sck.close(); 

     if (blnShutdown == true) { 
      String strSystem = mobjLocalIP.strGetIP(); 

      if (strSystem.compareTo(mobjLocalIP.strGetIP()) != 0) { 
     //Specified system is not the local system, issue message to remote system. 
       broadcastMessage("{\"" + JSON_LBL_TYPE + "\":\"" + 
                eMsgTypes.SHUTDOWN + "\"" 
           + ",\"" + JSON_LBL_TIME + "\":\"" + 
              clsTimeMan.lngTimeNow() + "\"}");        
      } else { 
    //Shutdown addressed to local system      
       if (getOS().indexOf("linux") >= 0) { 
     //TO DO!!!     
       } else if (getOS().indexOf("win") >= 0) { 
        Runtime runtime = Runtime.getRuntime(); 
        runtime.exec("shutdown /r /c \"Shutdown request\" /t 0 /f"); 
        System.exit(EXITCODE_REQUESTED_SHUTDOWN); 
       }    
      } 
     } 
    } catch (Exception ex) {    
    } finally { 
     if (sck != null) { 
      try { 
       sck.close(); 
      } catch (IOException ex) { 
       ex.printStackTrace(); 
      } 
     } 
    } 
} 

Я прочитал несколько спецификаций Отмеченные ответы, и насколько я могу судить, я отправляю данные в правильном формате, однако я ничего не получаю в браузере.

Возможно, я ошибочно полагаю, что браузер правильно скомпоновал бы куски в один, но я мог ошибаться. Обработчик клиентской стороны выглядит так:

 this.responseHandler = function() { 
try {  
    if (mobjHTTP == null 
    || !(mobjHTTP.readyState == 4 && mobjHTTP.status == 200) 
    || !(mstrResponseText = mobjHTTP.responseText) 
    || mstrResponseText.length == 0) { 
    //Not ready or no response to decode  
    return; 
    } 
    //Do something with the response 
    } catch(ex) { 
    T.error("responseHandler:", ex); 
} 

};

Этот обработчик настройки в другом месте в объекте:

mobjHTTP.onreadystatechange = this.responseHandler; 
+0

Зачем вам нужен ответ? TCP делает это уже –

+0

Я создаю ответ JSON, который может быть довольно большим> 4K. Некоторые браузеры, такие как IE, будут терпеть большие пакеты. Я хочу, чтобы решение работало для всех, сохраняя максимальный размер пакета до 768 байт на кусок. – SPlatten

+0

Я уверен, что у вас не будет проблем в каком-либо популярном браузере, существует ли ограничение на длину URL-адреса GET, но на ответ? Вы уверены, что у вас есть проблема? –

ответ

1

решаемые, не знаю почему, но удаление заголовка:

Transfer-Encoding: chunked 

а также кусок длины в начале каждого chunk разрешил проблему, я все еще записываю данные в 768 байтовых кусках. Это работает надежно и очень хорошо.

Не знаю, почему я должен был это сделать.

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

public static String[] arystrChunkData(String strData) { 
      int intChunks = (strData.length()/CHUNK_THRESHOLD_BYTESIZE) + 1; 
      String[] arystrChunks = new String[intChunks]; 
      int intLength = strData.length(), intPos = 0; 

      for(int c=0; c<arystrChunks.length; c++) {    
       if (intPos < intLength) { 
    //Extract a chunk from the data   
        int intEnd = Math.min(intLength, intPos + CHUNK_THRESHOLD_BYTESIZE); 
        arystrChunks[c] = strData.substring(intPos, intEnd); 
        intPos = intEnd; 
       } 
      }  
      return arystrChunks; 
     } 

петли, чтобы писать куски, не длин в начале и не 0 байт в конце кусков требуется:

String[] arystrChunks = arystrChunkData(strResponse); 
    for(String strChunk : arystrChunks) { 
      if (strChunk != null) { 
        out.write(strChunk.getBytes()); 
      }       
    } 
+0

Вы записываете данные в выходной поток в кусках 768 байт. Однако, я думаю, что после каждого куска не смывается. Не отправляя заголовок «Transfer-Encoding: chunked», а также не отправляя длину блока перед каждым куском; эффективно, вы отправляете полные данные в один отклик, когда поток вывода становится красным в конце. Разве вы не должны промывать выходной поток после написания каждого фрагмента? –

1

Как Я уже прокомментировал, что нет официального ограничения на размер ответа HTTP. TCP делает это для вас. Тем не менее, вы всегда можете настроить веб-сервер для реализации такой политики, установив для Content Browser максимальный размер Content-Length :: 32 бит Integer или 64 бит (см. here).

Технически вы можете иметь неограниченные ответы, используя Chunked Transfer, как вы заявляете на своем посту.Теоретически это используется для обхода максимального Content-Length.

Чаще всего, и если существует такое требование для огромного файла JSON (по крайней мере, некоторые MB), вы можете использовать какую-то логику разбиения на страницы с помощью последовательных запросов AJAX. В вашем случае вы можете разделить ваши большие данные JSON на программные фрагменты и отправить их по другому запросу AJAX. Затем пусть Javascript выполняет задачу слияния.

Как правило, JSON-ответ некоторых MB в размере будет успешно загружен в любом браузере. Предлагаю вам взглянуть на статью this; это 3-х лет, но я думаю, что в наши дни все еще лучше.

Вкратце, приведенный выше тест указывает, что JSON размером менее 35 МБ, вероятно, будет успешно загружен на любом современном настольном браузере. Это, однако, может быть не для мобильных браузеров. Например, есть reports для ограничений на использование сафари на> 10 МБ Json-файлах.

 Смежные вопросы

  • Нет связанных вопросов^_^