2015-10-27 125 views
4

我的工作在具有HTTP服务器内置的Java应用程序,此刻的服务器使用的ServerSocketChannel实现的,它侦听端口1694的请求:Java的HTTP服务器发送分块响应

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

我想实现的分块响应,在本分块响应不是由上面的代码支持。

[编辑]我已经尝试通过添加方法来实现分块响应:

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

我很确定你在任何流行的浏览器中都没有问题,GET url的长度有限制,但是对响应呢?你确定你有问题吗? –

回答

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-Length :: 32位整数最大大小或64位来配置Web服务器以实施此类策略(请参阅here)。

从技术上讲,您可以使用分块传输进行无限制的回复,就像您在帖子中陈述的一样。理论上,这用于绕过最大内容长度。

大多数情况下,如果需要巨大的JSON文件(至少有一些MB大小),可以通过顺序AJAX请求使用某种分页逻辑。在你的情况下,你可以将你的大JSON数据以编程方式分割为块,并通过另一个AJAX请求发送每个块。然后,让Javascript执行合并任务。

通常,某个MB大小的JSON响应将在任何浏览器上成功加载。我建议你看看this的文章;它已经3岁了,但我想现在情况会更好。

简而言之,上述基准指出,尺寸小于35 MB的JSON可能会在任何现代桌面浏览器上成功加载。但是,这对移动浏览器来说可能并非如此。例如,有一些reports移动Safari浏览器对> 10MB Json文件的限制。