2015-10-27 1 views
4

Je travaille sur une application Java qui a construit dans le serveur HTTP, au moment où le serveur est implémenté en utilisant ServerSocketChannel, il écoute sur le port 1694 pour les demandes:Java serveur HTTP envoi de réponse morcelées

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

A fil est installé pour gérer les demandes et les réponses:

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

Le fil est assez simple:

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

La majeure partie du code pour traiter la réponse est dans la fonction 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(); 
      } 
     } 
    } 
} 

Je voudrais mis en œuvre une réponse chunked, à l'heure actuelle des réponses morcelées ne sont pas pris en charge par le code ci-dessus.

[Modifier] J'ai essayé de mettre en œuvre une réponse chunked en ajoutant la méthode:

/** 
    * @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; 
} 

Le processRequest modifié ressemble maintenant à ceci:

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

J'ai lu plusieurs spécifications pour Réponses morcelées et autant que je sache, j'envoie des données dans le bon format, mais je ne reçois rien dans le navigateur.

J'ai peut-être supposé à tort que le navigateur regrouperait correctement les morceaux en un, mais je pourrais me tromper. Le gestionnaire côté client ressemble à ceci:

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

};

Ce gestionnaire est mis en place ailleurs dans l'objet:

mobjHTTP.onreadystatechange = this.responseHandler; 
+0

Pourquoi avez-vous besoin d'une réponse en bloc? TCP le fait déjà –

+0

Je crée une réponse JSON qui peut être assez grande> 4K. Certains navigateurs comme IE tolèrent les paquets plus volumineux. Je veux m'assurer que la solution fonctionne pour tous en gardant la taille de paquet maximum à 768 octets par morceau. – SPlatten

+0

Je suis assez sûr que vous n'aurez pas de problèmes dans n'importe quel navigateur populaire, il y a une limite sur la longueur de l'URL GET, mais sur la réponse? Êtes-vous sûr d'avoir un problème? –

Répondre

1

Solved ne sais pas pourquoi, mais en supprimant l'en-tête:

Transfer-Encoding: chunked 

Et aussi le morceau longueurs au début de chaque morceau résolu le problème, j'écris toujours les données en morceaux de 768 octets. Cela fonctionne de manière fiable et très bien.

Je ne sais pas pourquoi j'ai dû faire cela.

procédé final pour produire des morceaux de chaîne de données:

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

boucle pour écrire des morceaux, pas de longueurs au début et no 0 octet à la fin des morceaux requis:

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

Vous écrivez des données dans le flux de sortie par blocs de 768 octets. Cependant, je pense qu'il n'y a pas de rinçage après chaque morceau. En ne transmettant pas l'en-tête 'Transfer-Encoding: chunked' et en n'envoyant pas de longueur de bloc avant chaque bloc; En effet, vous envoyez les données complètes dans une réponse lorsque le flux de sortie est vidé à la fin. Ne devriez-vous pas vider le flux de sortie après avoir écrit chaque morceau? –

1

Comme J'ai déjà commenté, il n'y a pas de limite officielle sur la taille de la réponse HTTP. TCP fait ce travail pour vous. Toutefois, vous pouvez toujours configurer votre serveur Web pour implémenter une telle stratégie en définissant Content-Length :: Integer 32 bits ou 64 bits pour les navigateurs modernes (voir here). Techniquement, vous pouvez avoir des réponses illimitées en utilisant Chunked Transfer comme vous le dites dans votre message.En théorie, ceci est utilisé pour contourner la longueur maximale du contenu.

Le plus souvent, et s'il y a une telle exigence pour un énorme fichier JSON (au moins quelques Mo de taille), vous pouvez utiliser une sorte de logique de pagination via des requêtes AJAX séquentielles. Dans votre cas, vous pouvez diviser vos grandes données JSON en morceaux et les envoyer par une autre requête AJAX. Ensuite, laissez Javascript exécuter la tâche de fusion.

Généralement, une réponse JSON de quelques MB se chargera avec succès sur n'importe quel navigateur. Je vous suggère de jeter un oeil sur l'article this; il a 3 ans, mais je suppose que les choses sont encore meilleures de nos jours. En bref, le benchmark ci-dessus indique que JSON de taille inférieure à 35 Mo se chargera probablement avec succès sur n'importe quel navigateur de bureau moderne. Cependant, cela peut ne pas être le cas pour les navigateurs mobiles. Par exemple, il existe quelques reports pour les limitations de safari mobile sur les fichiers JSON> 10 Mo.