[英]How do I get the body from this example HTTP request?
我試圖找到最簡單的方法來解析Java中的RFC-822文檔。 假設我有一個存儲HTTP消息的消息隊列。 請求和響應。 因此,通過建立與端口80的套接字連接並從該端口發送/檢索消息,不能以“正常”方式檢索它們。
在下面的代碼中,我故意將“郵件”標頭與HTTP消息混合在一起。 這是為了表明兩者之間沒有太大區別。 但這不是重點。 這是代碼:
package httpexample;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import org.apache.http.Header;
import org.apache.http.HttpException;
import org.apache.http.HttpRequest;
import org.apache.http.impl.io.DefaultHttpRequestParser;
import org.apache.http.impl.io.HttpTransportMetricsImpl;
import org.apache.http.impl.io.SessionInputBufferImpl;
import org.apache.http.io.HttpMessageParser;
import org.apache.http.message.BasicHttpEntityEnclosingRequest;
public class HttpExample {
// RFC 822
public static void main(String[] args) throws IOException, HttpException {
String str = "POST http://localhost:8080/foobar/1234567 HTTP/1.1\n" +
"Message-ID: <19815303.1075861029555.JavaMail.ss@kk>\n" +
"Date: Wed, 6 Mar 2010 12:32:20 -0800 (PST)\n" +
"From: someone@someotherplace.com\n" +
"To: someone@someplace.com\n" +
"Subject: some subject\n" +
"Mime-Version: 1.0\n" +
"Content-Type: text/plain; charset=us-ascii\n" +
"Content-Transfer-Encoding: 7bit\n" +
"X-From: one, some <some.one@someotherplace.com>\n" +
"X-To: one\n" +
"X-cc: \n" +
"X-bcc: \n" +
"X-Origin: Bob-R\n" +
"X-FileName: rbob (Non-Privileged).pst\n" +
"\n" +
"some message\n";
ByteArrayInputStream fakeStream = new ByteArrayInputStream(
str.getBytes());
HttpTransportMetricsImpl metrics = new HttpTransportMetricsImpl();
SessionInputBufferImpl inbuffer = new SessionInputBufferImpl(metrics, 1024);
inbuffer.bind(fakeStream);
HttpMessageParser<HttpRequest> requestParser =
new DefaultHttpRequestParser(inbuffer);
BasicHttpEntityEnclosingRequest request = (BasicHttpEntityEnclosingRequest)requestParser.parse();
for (Header hdr : request.getAllHeaders()) {
System.out.println(String.format("%-30s = %s", hdr.getName(), hdr.getValue()));
}
System.out.println(String.format("Request Line: %s", request.getRequestLine()));
System.out.println(String.format("Body\n------------------\n%s",
request.getEntity()));
}
}
輸出看起來像這樣:
Message-ID = <19815303.1075861029555.JavaMail.ss@kk>
Date = Wed, 6 Mar 2010 12:32:20 -0800 (PST)
From = someone@someotherplace.com
To = someone@someplace.com
Subject = some subject
Mime-Version = 1.0
Content-Type = text/plain; charset=us-ascii
Content-Transfer-Encoding = 7bit
X-From = one, some <some.one@someotherplace.com>
X-To = one
X-cc =
X-bcc =
X-Origin = Bob-R
X-FileName = rbob (Non-Privileged).pst
Request Line: POST http://localhost:8080/foobar/1234567 HTTP/1.1
Body
------------------
null
我想不通,是如何訪問消息的主體 。
我希望它的內容some message\\n
我在BasicHttpEntityEnclosingRequest
中找不到任何可以提供此值的方法。 在較早的版本中,我使用了
HttpRequest request = requestParser.parse();
代替
BasicHttpEntityEnclosingRequest request =
(BasicHttpEntityEnclosingRequest) requestParser.parse();
我將其更改為BasicHttpEntityEnclosingRequest
因為它具有getEntity
方法。 但這返回null
。
所以我有點迷路。
我在哪里找到屍體?
我添加了Content-Length標頭,否則解析器將忽略POST正文。 我已經修改了您的代碼,現在它可以很好地解析主體了:
package org.apache.http.examples;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import org.apache.http.Header;
import org.apache.http.HttpException;
import org.apache.http.message.BasicHttpEntityEnclosingRequest;
import org.apache.http.util.EntityUtils;
public class HttpExample {
// RFC 822
public static void main(String[] args) throws IOException, HttpException {
String str = "POST http://localhost:8080/foobar/1234567 HTTP/1.1\n" +
"Message-ID: <19815303.1075861029555.JavaMail.ss@kk>\n" +
"Date: Wed, 6 Mar 2010 12:32:20 -0800 (PST)\n" +
"From: someone@someotherplace.com\n" +
"To: someone@someplace.com\n" +
"Subject: some subject\n" +
"Mime-Version: 1.0\n" +
"Content-Type: text/plain; charset=us-ascii\n" +
"Content-Transfer-Encoding: 7bit\n" +
"X-From: one, some <some.one@someotherplace.com>\n" +
"X-To: one\n" +
"X-cc: \n" +
"X-bcc: \n" +
"X-Origin: Bob-R\n" +
"X-FileName: rbob (Non-Privileged).pst\n" +
"Content-Length: 13\n" +
"\n" +
"some message\n";
ByteArrayInputStream fakeStream = new ByteArrayInputStream(
str.getBytes());
BHttpConnectionBaseImpl b = new BHttpConnectionBaseImpl(fakeStream);
BasicHttpEntityEnclosingRequest request1 = (BasicHttpEntityEnclosingRequest) b.receiveRequestHeader();
b.receiveRequestEntity(request1);
for (Header hdr : request1.getAllHeaders()) {
System.out.println(String.format("%-30s = %s", hdr.getName(), hdr.getValue()));
}
System.out.println(String.format("Request Line: %s", request1.getRequestLine()));
System.out.println(String.format("Body\n------------------\n%s",
EntityUtils.toString( request1.getEntity() ) ));
}
}
class BHttpConnectionBaseImpl extends org.apache.http.impl.DefaultBHttpServerConnection{
private InputStream inputStream;
public BHttpConnectionBaseImpl(final InputStream inputStream) {
super(4048);
this.inputStream = inputStream;
try {
super.bind(new Socket());
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
protected InputStream getSocketInputStream(final Socket socket) throws IOException {
return inputStream;
}
@Override
protected OutputStream getSocketOutputStream(final Socket socket) throws IOException {
return new ByteArrayOutputStream();
}
}
POST正文的解析在org.apache.http.impl.BHttpConnectionBase.prepareInput(HttpMessage)
,無論其唯一的構造方法是受保護的並且需要很多參數。 子org.apache.http.impl.DefaultBHttpServerConnection
有一個方便的公共構造函數,並在receiveRequestHeader()
中進行頭解析。 我正在重載的方法需要繞過一些錯誤檢查,例如Socket == null
並能夠從fakeStream
讀取請求
盡管我尚未測試過,但另一種可行的方法是重寫Socket
尤其是重寫其getInputStream()
和getOutputStream()
。 然后創建DefaultBHttpServerConnection
的實例並調用其bind
方法。 其余應相同。
我認為問題可能在於您的消息標題不清楚主體的長度,因此接收方只是忽略了它。 HTTP規范定義了幾種有關如何傳達此信息的選項,但似乎沒有一個選項適用於此:
Content-Transfer-Encoding
必須為Transfer-Encoding
7bit
不在標准選項之列 。 str.getBytes()
,它將為您提供UTF-16字節,這不是在Content-Type
聲明的us-ascii
。 因此,我會稍微更改您的請求:
Content-Type: text/plain; charset=UTF-16
Content-Type: text/plain; charset=UTF-16
Content-Transfer-Encoding
Content-Lenght: 28
(28是"some message\\n".getBytes().length()
)。 查看DefaultHttpRequestParser的源代碼,似乎它僅解析請求行和標頭,而不嘗試解析正文。
通過覆蓋LineParser自定義解析頭:
inbuffer = new SessionInputBufferImpl(new HttpTransportMetricsImpl(), reqDataLength);
inbuffer.bind(input);
HttpMessageParser<org.apache.http.HttpRequest> requestParser = new DefaultHttpRequestParser(
inbuffer,
new LineParser(),
new DefaultHttpRequestFactory(),
MessageConstraints.DEFAULT
);
獲取實體主體,如下所示:
HttpEntityEnclosingRequest ereq = (HttpEntityEnclosingRequest) req;
ContentLengthStrategy contentLengthStrategy =
StrictContentLengthStrategy.INSTANCE;
long len = contentLengthStrategy.determineLength(req);
InputStream contentStream = null;
if (len == ContentLengthStrategy.CHUNKED) {
contentStream = new ChunkedInputStream(buf);
} else if (len == ContentLengthStrategy.IDENTITY) {
contentStream = new IdentityInputStream(buf);
} else {
contentStream = new ContentLengthInputStream(buf, len);
}
BasicHttpEntity ent = new BasicHttpEntity();
ent.setContent(contentStream);
ereq.setEntity(ent);
return ereq;
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.