Domanda

Ho un problema con i Comuni Jakarta HttpClient. Prima la mia auto-scritto HTTPServer ottiene la vera richiesta v'è una richiesta che è completamente vuoto. Questo è il primo problema. Il primo problema è risolto. E 'stato causato da un inutile URLConnection Il secondo problema è che a volte i dati di richiesta termina dopo la terza o la quarta linea della richiesta http:

POST / HTTP/1.1
User-Agent: Jakarta Commons-HttpClient/3.1
Host: 127.0.0.1:4232

Per il debugging Sto usando l'Asse TCPMonitor. C'è ogni cose è bene, ma la richiesta vuota.

Come elaborare il flusso:

StringBuffer requestBuffer = new StringBuffer();

InputStreamReader is = new InputStreamReader(socket.getInputStream(), "UTF-8");

int byteIn = -1;
do {
    byteIn = is.read();
    if (byteIn > 0) {
        requestBuffer.append((char) byteIn);
    }
} while (byteIn != -1 && is.ready());

String requestData = requestBuffer.toString();

Trovato un nuovo modo di elaborare il flusso. Ho letto tutti i parametri di intestazione e utilizzare il 'Content-Length' per la lettura dei dati di post.

InputStream is = mySocket.getInputStream();
if (is == null) {
    return;
}
BufferedReader in = new BufferedReader(new InputStreamReader(is, "UTF-8"));

// Read the request line
// ...
// ...

// Parse the header
Properties header = new Properties();
if (st.hasMoreTokens()) {
    String line = in.readLine();
    while (line != null && line.trim().length() > 0) {
        int p = line.indexOf(':');
        header.put(line.substring(0, p).trim().toLowerCase(), line.substring(p + 1).trim());
        line = in.readLine();
    }
}

// If the method is POST, there may be parameters
// in data section, too, read it:
String postLine = "";
if (method.equalsIgnoreCase("POST")) {
    long size = 0x7FFFFFFFFFFFFFFFl;
    String contentLength = header.getProperty("content-length");
    if (contentLength != null) {
        try {
            size = Integer.parseInt(contentLength);
        } catch (NumberFormatException ex) {
        }
    }
    postLine = "";
    char buf[] = new char[512];
    int read = in.read(buf);
    while (read >= 0 && size > 0 && !postLine.endsWith("\r\n")) {
        size -= read;
        postLine += String.valueOf(buf, 0, read);
        if (size > 0) {
            read = in.read(buf);
        }
    }
    postLine = postLine.trim();
    decodeParms(postLine, parms);
}

Come mando la richiesta:

client.getParams().setSoTimeout(30000);

method = new PostMethod(url.getPath());
method.getParams().setContentCharset("utf-8");
method.setRequestHeader("Content-Type", "application/xml; charset=utf-8");
method.addRequestHeader("Connection", "close");
method.setFollowRedirects(false);

byte[] requestXml = getRequestXml();

method.setRequestEntity(new InputStreamRequestEntity(new ByteArrayInputStream(requestXml)));

client.executeMethod(method);

int statusCode = method.getStatusCode();

hai nessuno di un'idea su come risolvere questi problemi il problema?

Alex

È stato utile?

Soluzione

Potrebbe essere a che fare con la seconda condizione nel vostro ciclo while, il metodo isReady () potrebbe restituire false quando la prossima lettura potrebbe bloccare - ma non mi interessa se blocca o no, in modo che possiamo semplicemente rimuovere esso (si può leggere di più qui: http://java.sun.com/j2se/1.5.0/docs/api/java/io/InputStreamReader.html#ready%28%29 ). Provare a cambiare a questo:

byte[] buf = new byte[500];
while((is.read(buf))>-1){
  requestBuffer.append(new String(buf).trim());
  buf = new byte[500];
}

Ora si dovrebbe ottenere l'intera richiesta.

Altri suggerimenti

Non so circa il primo problema, ma penso che il tuo secondo problema è dovuto a questo:

} while (byteIn != -1 && is.ready());

Se il mittente non è abbastanza veloce l'invio di dati, il ricevitore può chiamare is.ready() prima che il prossimo pacchetto è stato inviato. Questo farà sì che is.ready() per tornare false che farà sì che il ciclo di fermarsi.

La correzione minima è di cambiare quella linea a:

} while (byteIn != -1);

Modifica

Ma in realtà, è necessario riscrivere il metodo lungo le linee di risposta di @ simonlord. Si tratta di una pessima idea di leggere un buffer flusso di un byte alla volta. Si finisce per fare una chiamata di sistema per ogni chiamata read, che è terribilmente inefficiente.

Modifica 2

La ragione per cui la rimozione is.ready() causato ritardi è perché non pagavano la giusta attenzione al protocollo HTTP. Il problema è stato il codice HttpClient teneva il lato richiesta di connessione TCP aperta per consentire il collegamento da riutilizzare. La soluzione più semplice (ma subottimale) sarebbe stato per configurare HttpClient per chiudere il lato richiesta della connessione. Il tuo codice sarebbe poi visto l'EOF subito. Quello che effettivamente fatto è stato un'altra soluzione.

Francamente non si dovrebbe essere ancora cercare per implementare il protocollo HTTP sul lato server se non si è preparati a comprendere l'intera specifica HTTP in modo approfondito e implementare fedelmente. Le probabilità sono che un'implementazione esistente sarà più veloce e più affidabile di tutto ciò che si può mettere insieme. Il problema con l'attuazione di un sottoinsieme delle specifiche è che il server può avere bisogno di parlare con un vero e proprio browser che utilizza parti della specifica che non si è preso la briga di implementare / test.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top