Android デバイスからTomcatサーバーに XML をポストしようとしていますが、ストリームにゼロ バイトが含まれています。400 bad request response を受け取りましたが、何が問題なのかわかりません。Android とサーバーのマシンからブラウザーで Web アプリケーションにアクセスできます。XML をログに記録すると、問題ないように見えます。400: bad request が表示されるのはなぜですか?
[更新 4]: Wiresharkでリクエストをインターセプトし、(Len=0) Length of zero を取得しました。なぜだかはまだわかりませんが。
[更新 3]: 10.0.2.2 に投稿すると、connection to http://10.0.2.2:8080/Archery refused
. サーバーの実際のIP アドレスに投稿すると、不正な要求が返されます。
[更新 2]: logcat
...
08-06 15:32:39.189 W/myApp (2064): xstream created
08-06 15:32:39.269 W/myApp (2064): xml created
08-06 15:32:39.269 E/test (2064): <html><head></head><body>Why don't you work?</body></html>
08-06 15:32:39.269 E/test (2064): XML set to String Entity
08-06 15:32:39.269 E/test (2064): post headers set
08-06 15:32:39.269 E/test (2064): Sending post
08-06 15:32:39.319 W/InputManagerService(239): Window already focused, ignoring focus gain of: com.android.internal.view.IInputMethodClient$Stub$Proxy@2bc4a7c0
08-06 15:32:39.339 E/test (2064): Post sent, response is: HTTP/1.1 400 Bad Request[Lorg.apache.http.Header;@2c0695d0org.apache.http.impl.client.ClientParamsStack@2c1a4cd0
08-06 15:32:41.309 D/OpenGLRenderer(337): Flushing caches (mode 0)
08-06 15:32:41.409 W/InputManagerService(239): Window already focused, ignoring focus gain of: com.android.internal.view.IInputMethodClient$Stub$Proxy@2bc79268
08-06 15:32:41.589 I/ActivityManager(239): START {act=android.intent.action.MAIN cat=[android.intent.category.HOME] flg=0x10200000 cmp=com.cyanogenmod.trebuchet/.Launcher} from pid 239
...
[更新 1]:私の要求が次のような場合:
StringEntity se = new StringEntity(xmlString, "UTF-8");
Log.e("test", "XML set to String Entity");
se.setContentType("text/xml");
post.setEntity(se);
post.setHeader("Content-Type", "text/xml; charset=utf-8");
post.setHeader("Host", "http://xxx.xxx.x.x:8080/Archery");
Log.e("test", "post headers set");
RequestDumpFilter を使用すると、これがログに記録されます。
INFO: Request Received at 2013-08-06 13:27:01.342
characterEncoding=null
contentLength=-1
contentType=null
locale=en_US
locales=en_US, en
protocol=HTTP/1.1
remoteAddr=0:0:0:0:0:0:0:1
remoteHost=0:0:0:0:0:0:0:1
scheme=http
serverName=localhost
serverPort=8080
isSecure=false
---------------------------------------------
contextPath=
header=host=localhost:8080
header=user-agent=Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:22.0) Gecko/20100101 Firefox/22.0
header=accept=text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
header=accept-language=en-US,en;q=0.5
header=accept-encoding=gzip, deflate
header=connection=keep-alive
header=cache-control=max-age=0
method=GET
pathInfo=null
queryString=null
remoteUser=null
requestedSessionId=null
requestURI=/Archery
servletPath=/Archery
=============================================
また、コンテンツ長ヘッダーを追加するpost.setHeader("Content-Length", Long.toString(se.getContentLength()));
と、プログラムが ClientProtocolException でクラッシュします。
サーバーの processRequest メソッド:
protected void processRequest(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
//String xmlSent = req.toString();
resp.setContentType("text/html;charset=UTF-8");
PrintWriter pw = resp.getWriter();
InputStream xmlStream = req.getInputStream();
if (xmlStream != null){
pw.println("XML stream: " + xmlStream.available());
}
else{
pw.println("No XML stream found");
}
String xmlSent = convertStreamToString(xmlStream);
ShootRecord recordSent = XMLTransformer.xmlToObject(xmlSent);
if(recordSent!=null){
String date = recordSent.listOfScoreSheets.get(0).getmDate();
String target = recordSent.listOfScoreSheets.get(0).getmTargetNumber();
String dateTargetKey = date + target;
shootRecordMap.put(dateTargetKey, recordSent);
}
//out.write(xmlSent.getBytes());
if (recordSent != null){
pw.println("Date of record sent: "+recordSent.shootRecordDate);
}
else{
pw.println("No record received yet");
}
pw.flush();
pw.close();
}
// <editor-fold defaultstate="collapsed" desc="HttpServlet methods. doGet and doPost call processRequest">
// </editor-fold>
postToServletOverWifi メソッド
public boolean postToServletOverWifi(ShootRecord recToSend, Context context)
{
try
{
Log.w("myApp", "starting method postToServletOverWifi");
/* Prepare object as XML */
XStream xstream = new XStream();
xstream.processAnnotations(ScoreSheet.class);
xstream.processAnnotations(ShootRecord.class);
Log.w("myApp", "xstream created");
ArrayList<ScoreSheet> mListOfScoreSheets = recToSend.getListOfScoreSheets();
ShootRecord testShootRecord = new ShootRecord();
testShootRecord.setmShootRecordDate(recToSend.getRecordDate());
testShootRecord.setmNumArchersOnTarget(recToSend.getNumArchersOnTarget());
testShootRecord.setmScoreSheetTypeIndex(recToSend.getScoreSheetType());
testShootRecord.setmShootRecordName(recToSend.getmShootRecordName());
testShootRecord.setmListOfScoreSheets(mListOfScoreSheets);
String xml = xstream.toXML(testShootRecord);
Log.w("myApp", "XML created");
new taskForPostingToServer(xml).execute();
// p.flush();
// ostream.close();
return true;
}
catch (Exception e) {
System.out.println( e.getMessage() );
e.printStackTrace();
return false;
}
}
Android タスク
public taskForPostingToServer(String xml)
{
xmlString = xml;
client = new DefaultHttpClient();
url = "http://xxx.xxx.x.x:8080/Archery";
post = new HttpPost(url);
//post.setHeader("Content-type", "text/xml; charset=utf-8");
post.setHeader("host", "http://xxx.xxx.x.x:8080/Archery");
response = null;
}
protected void onPreExecute()
{
//StringEntity se = null;
try {
//se = new StringEntity(xmlString, "UTF-8");
//post.setEntity(se);
Log.e("test", xmlString);
InputStream inputStream=new ByteArrayInputStream(xmlString.getBytes()); //Init your own inputstream
InputStreamEntity inputStreamEntity=new InputStreamEntity(inputStream, xmlString.getBytes().length);
post.setEntity(inputStreamEntity);
post.setHeader("Content-Type", "text/xml;charset=UTF-8");
}
catch (Exception ex) {
Logger.getLogger(ScoreSheetsView.class.getName()).log(Level.SEVERE, null, ex);
}
}
protected Boolean doInBackground(Integer... params)
{
boolean success = true;
try {
Log.e("test", "Sending post");
response = client.execute(post);
Log.e("test", "Post sent, "+ "response is: "+response.getStatusLine());
}
catch (IOException ex) {
Logger.getLogger(ScoreSheetsView.class.getName()).log(Level.SEVERE, null, ex);
}
if (response == null){
success =false;
}
return success;
}
...