Android HTTPPost 返回错误“方法不允许。”

发布于 2024-11-19 11:38:19 字数 5070 浏览 5 评论 0原文

我正在编写一个 Android 2.2 应用程序,它将 json 严格性 POST 到 ReSTfull Web 服务。

Fiddler 调用 Web 服务时会按预期返回相同的 Json,并且具有相同 Json 的 aspx Web 应用程序也会按预期返回。

当我查看服务器日志时,我可以看到服务器正在使用 307 重定向响应初始 POST 动词,然后立即响应 GET 和 405 错误。

Fiddler 和 aspx 应用程序使用 307 重定向记录一个 POST,然后立即记录另一个 POST 和 200 OK。

到底是怎么回事?

这是主要活动:

package com.altaver.android_PostJson2;

import org.json.JSONException;
import org.json.JSONObject;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;

public class PostJson extends Activity {
     private static final String TAG = "MainActivity";
     private static final String URL = "http://web2.altaver.com/sdz/avReSTfulLogin1";

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        JSONObject jsonObjSend = new JSONObject();

        try {
         jsonObjSend.put("Pass", "sz");
         jsonObjSend.put("User", "szechman");


         Log.i(TAG, jsonObjSend.toString(2));

        } catch (JSONException e) {
            e.printStackTrace();
        }

        JSONObject jsonObjRecv = HttpClient.SendHttpPost(URL, jsonObjSend);            

//examine JSONObject later
    }
}

这是执行 Web 服务调用的类代码:

package com.altaver.android_PostJson2;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.params.HttpClientParams;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.json.JSONObject;

import android.util.Log;

public class HttpClient {

    private static final String TAG = "HttpClient";


    public static JSONObject SendHttpPost(String URL, JSONObject jsonObjSend) {

          try {
           DefaultHttpClient httpclient = new DefaultHttpClient();

           HttpClientParams.setRedirecting(httpclient.getParams(), true);

           //added cookie policy, wild shot in the dark
           //httpclient.getParams().setParameter(ClientPNames.COOKIE_POLICY, >CookiePolicy.RFC_2109);

           HttpPost httpPostRequest = new HttpPost(URL);

           StringEntity se;
           se = new StringEntity(jsonObjSend.toString());

           // Set HTTP parameters
           httpPostRequest.setEntity(se);

           //httpPostRequest.setHeader("User-Agent", >"com.altaver.android_PostJson2");
           httpPostRequest.setHeader("User-Agent", "Mozilla/5.0 (Windows; U; >Windows NT 5.1; en-US; rv:1.9.2.3) Gecko/20100401");

           httpPostRequest.setHeader("Accept", "application/json");
           httpPostRequest.setHeader("Content-Type", "application/json");

           long t = System.currentTimeMillis();
           HttpResponse response = (HttpResponse) >httpclient.execute(httpPostRequest);
           Log.i(TAG, "HTTPResponse received in [" + >(System.currentTimeMillis()-t) + "ms]");

           HttpEntity entity = response.getEntity();

           if (entity != null) {
            InputStream instream = entity.getContent();
            Header contentEncoding = response.getFirstHeader("Content-Encoding");


            String resultString= convertStreamToString(instream);
            instream.close();
            resultString = resultString.substring(1,resultString.length()-1); // >remove wrapping "[" and "]"

            JSONObject jsonObjRecv = new JSONObject(resultString);
            Log.i(TAG,"<jsonobject>\n"+jsonObjRecv.toString()+"\n</jsonobject>");

            return jsonObjRecv;
           } 

          }
          catch (Exception e)
          {
           e.printStackTrace();
          }
          return null;
         }

    private static String convertStreamToString(InputStream is) {
          /*
           * To convert the InputStream to String we use the >BufferedReader.readLine()
           * method. We iterate until the BufferedReader return null which means
           * there's no more data to read. Each line will appended to a >StringBuilder
           * and returned as String.
           * 
           * (c) public domain: http://senior.ceng.metu.edu.tr/2009/praeda/2009/01>/11/a-simple-restful-client-at-android/
           */
          BufferedReader reader = new BufferedReader(new InputStreamReader(is));
          StringBuilder sb = new StringBuilder();

          String line = null;
          try {
           while ((line = reader.readLine()) != null) {
            sb.append(line + "\n");
           }
          } catch (IOException e) {
           e.printStackTrace();
          } finally {
           try {
            is.close();
           } catch (IOException e) {
            e.printStackTrace();
           }
          }
          return sb.toString();
    }
}

I'm coding an Android 2.2 app that POSTs a json stringentity to a ReSTfull web service.

Fiddler calls to the web service with identical Json return as expected, and an aspx web application with identical Json returns as expected.

When I look at the server logs, I can see that the server is responding to an initial POST verb with a 307 redirect, then immediately a GET and 405 error.

Fiddler and the aspx application log a POST with a 307 redirect, then immediately another POST and a 200 OK.

What is going on?

This is the main activity:

package com.altaver.android_PostJson2;

import org.json.JSONException;
import org.json.JSONObject;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;

public class PostJson extends Activity {
     private static final String TAG = "MainActivity";
     private static final String URL = "http://web2.altaver.com/sdz/avReSTfulLogin1";

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        JSONObject jsonObjSend = new JSONObject();

        try {
         jsonObjSend.put("Pass", "sz");
         jsonObjSend.put("User", "szechman");


         Log.i(TAG, jsonObjSend.toString(2));

        } catch (JSONException e) {
            e.printStackTrace();
        }

        JSONObject jsonObjRecv = HttpClient.SendHttpPost(URL, jsonObjSend);            

//examine JSONObject later
    }
}

This is the class code doing the web service call:

package com.altaver.android_PostJson2;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.params.HttpClientParams;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.json.JSONObject;

import android.util.Log;

public class HttpClient {

    private static final String TAG = "HttpClient";


    public static JSONObject SendHttpPost(String URL, JSONObject jsonObjSend) {

          try {
           DefaultHttpClient httpclient = new DefaultHttpClient();

           HttpClientParams.setRedirecting(httpclient.getParams(), true);

           //added cookie policy, wild shot in the dark
           //httpclient.getParams().setParameter(ClientPNames.COOKIE_POLICY, >CookiePolicy.RFC_2109);

           HttpPost httpPostRequest = new HttpPost(URL);

           StringEntity se;
           se = new StringEntity(jsonObjSend.toString());

           // Set HTTP parameters
           httpPostRequest.setEntity(se);

           //httpPostRequest.setHeader("User-Agent", >"com.altaver.android_PostJson2");
           httpPostRequest.setHeader("User-Agent", "Mozilla/5.0 (Windows; U; >Windows NT 5.1; en-US; rv:1.9.2.3) Gecko/20100401");

           httpPostRequest.setHeader("Accept", "application/json");
           httpPostRequest.setHeader("Content-Type", "application/json");

           long t = System.currentTimeMillis();
           HttpResponse response = (HttpResponse) >httpclient.execute(httpPostRequest);
           Log.i(TAG, "HTTPResponse received in [" + >(System.currentTimeMillis()-t) + "ms]");

           HttpEntity entity = response.getEntity();

           if (entity != null) {
            InputStream instream = entity.getContent();
            Header contentEncoding = response.getFirstHeader("Content-Encoding");


            String resultString= convertStreamToString(instream);
            instream.close();
            resultString = resultString.substring(1,resultString.length()-1); // >remove wrapping "[" and "]"

            JSONObject jsonObjRecv = new JSONObject(resultString);
            Log.i(TAG,"<jsonobject>\n"+jsonObjRecv.toString()+"\n</jsonobject>");

            return jsonObjRecv;
           } 

          }
          catch (Exception e)
          {
           e.printStackTrace();
          }
          return null;
         }

    private static String convertStreamToString(InputStream is) {
          /*
           * To convert the InputStream to String we use the >BufferedReader.readLine()
           * method. We iterate until the BufferedReader return null which means
           * there's no more data to read. Each line will appended to a >StringBuilder
           * and returned as String.
           * 
           * (c) public domain: http://senior.ceng.metu.edu.tr/2009/praeda/2009/01>/11/a-simple-restful-client-at-android/
           */
          BufferedReader reader = new BufferedReader(new InputStreamReader(is));
          StringBuilder sb = new StringBuilder();

          String line = null;
          try {
           while ((line = reader.readLine()) != null) {
            sb.append(line + "\n");
           }
          } catch (IOException e) {
           e.printStackTrace();
          } finally {
           try {
            is.close();
           } catch (IOException e) {
            e.printStackTrace();
           }
          }
          return sb.toString();
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

生活了然无味 2024-11-26 11:38:19

在 URL 末尾添加“/”会导致发生重定向,因为您的服务器喜欢以“/”结尾的 URL。服务器将您重定向到的 URL 完全支持 POST,但客户端在其行为根据您的 setRedirecting() 调用时执行 GET 请求(cURL 使用 -L 开关执行相同的操作)解决方法是要么将URL 末尾的“/”,或者自己从响应中获取 Location 标头,然后手动发起另一个 POST 请求。

这可以在wireshark中观察到。您可以通过尝试使用浏览器对附加斜杠的 URL 执行 GET 请求来测试该理论。这将导致浏览器收到 405。这是 Android 的固定代码,此代码使用在 URL 附加“/”的简单修复(未准备好生产):

 package com.altaver.demo;

import java.io.IOException;
import java.io.UnsupportedEncodingException;

import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.HttpResponseException;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.params.HttpClientParams;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.BasicResponseHandler;
import org.apache.http.impl.client.DefaultHttpClient;
import org.json.JSONException;
import org.json.JSONObject;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.widget.Toast;

public class AltaVerDemoActivity extends Activity {
    private static final String TAG = "MainActivity";
    private static final String URL = "http://96.56.2.188/sdz/avReSTfulLogin1/";

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        JSONObject jsonObjSend = new JSONObject();
        try {
            jsonObjSend.put("Pass", "sz");
            jsonObjSend.put("User", "szechman");
        } catch (JSONException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        HttpClient client = new DefaultHttpClient();
        HttpPost httpPostRequest = new HttpPost(URL);
        httpPostRequest.setHeader("User-Agent", "com.altaver.android_PostJson2");
        httpPostRequest.setHeader("Accept", "application/json");
        httpPostRequest.setHeader("Content-Type", "application/json");
        StringEntity se = null;
        try {
            se = new StringEntity(jsonObjSend.toString());
        } catch (UnsupportedEncodingException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        httpPostRequest.setEntity(se);
        HttpResponse response = null;
        try {
            response = client.execute(httpPostRequest);
        } catch (ClientProtocolException e) {
            // TODO Auto-generated catch block
            Toast.makeText(getApplicationContext(),
                    "Please check your internet connection",
                    Toast.LENGTH_SHORT).show();
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        BasicResponseHandler responseHandler = new BasicResponseHandler();
        String strResponse = null;
        if (response != null) {
            try {
                strResponse = responseHandler.handleResponse(response);
            } catch (HttpResponseException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        Log.e("AltaVerDemoActivity", "Response: " + strResponse);
    }
}

Putting a '/' at the end of URL causes the redirect to happen because your server likes urls that end in '/'. POST is fully supported by the URL your server redirects you to, but the client is executing a GET request when it behaves according to your setRedirecting() call (cURL does the same exact thing with the -L switch) The fix is to either put a '/' at the end of URL, or to grab the Location header from the response yourself and then initiate another POST request manually.

This can be observed in wireshark. You can test the theory by trying to perform a GET request with your browser to the URL with a slash appended to it. That will cause the browser to get a 405. Here's the fixed code for Android, this code uses the simple fix of appending a '/' to the URL (not production ready):

 package com.altaver.demo;

import java.io.IOException;
import java.io.UnsupportedEncodingException;

import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.HttpResponseException;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.params.HttpClientParams;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.BasicResponseHandler;
import org.apache.http.impl.client.DefaultHttpClient;
import org.json.JSONException;
import org.json.JSONObject;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.widget.Toast;

public class AltaVerDemoActivity extends Activity {
    private static final String TAG = "MainActivity";
    private static final String URL = "http://96.56.2.188/sdz/avReSTfulLogin1/";

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        JSONObject jsonObjSend = new JSONObject();
        try {
            jsonObjSend.put("Pass", "sz");
            jsonObjSend.put("User", "szechman");
        } catch (JSONException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        HttpClient client = new DefaultHttpClient();
        HttpPost httpPostRequest = new HttpPost(URL);
        httpPostRequest.setHeader("User-Agent", "com.altaver.android_PostJson2");
        httpPostRequest.setHeader("Accept", "application/json");
        httpPostRequest.setHeader("Content-Type", "application/json");
        StringEntity se = null;
        try {
            se = new StringEntity(jsonObjSend.toString());
        } catch (UnsupportedEncodingException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        httpPostRequest.setEntity(se);
        HttpResponse response = null;
        try {
            response = client.execute(httpPostRequest);
        } catch (ClientProtocolException e) {
            // TODO Auto-generated catch block
            Toast.makeText(getApplicationContext(),
                    "Please check your internet connection",
                    Toast.LENGTH_SHORT).show();
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        BasicResponseHandler responseHandler = new BasicResponseHandler();
        String strResponse = null;
        if (response != null) {
            try {
                strResponse = responseHandler.handleResponse(response);
            } catch (HttpResponseException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        Log.e("AltaVerDemoActivity", "Response: " + strResponse);
    }
}
那一片橙海, 2024-11-26 11:38:19

如果服务中的请求类型是WebGet,例如

WebGet(UriTemplate = "login/?name={name}&password={password}", ResponseFormat = WebMessageFormat.Json)"

您尝试通过android使用HttpPost访问该方法,则经常会出现上述问题。

我有同样的问题,我花了几个小时才弄清楚。

The above issue often occurs if the request type in the service is WebGet e.g

WebGet(UriTemplate = "login/?name={name}&password={password}", ResponseFormat = WebMessageFormat.Json)"

and you try to access the method using HttpPost via android.

I have the same issue and it took me hours just to figure it out.

零時差 2024-11-26 11:38:19

我看了上面的答案,似乎有点太复杂了!

我为解决这个问题所做的一切(正如一些答案所述,是由于不允许 POST 的服务),就是更改:

HttpPost post = new HttpPost(params[0]);
HttpResponse response = client.execute(post);

因为

HttpGet get = new HttpGet(params[0]);
HttpResponse response = client.execute(get);

这样就解决了它!

PD:我收到状态代码:405!

I Watched The Above Answers And Seems A Little Too Much Complicated!!

All I Did To Solve This(Which As Some Of The Answers States, Is Due The Service That Doesn't Allow The POST), Is To Change:

HttpPost post = new HttpPost(params[0]);
HttpResponse response = client.execute(post);

For

HttpGet get = new HttpGet(params[0]);
HttpResponse response = client.execute(get);

And That Solved It!

PD: I Was Getting Status Code: 405!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文