在Android中发送HTTP DELETE请求

29

我的客户端API规定,要删除对象,必须发送一个DELETE请求,其中包含描述内容的Json头数据。实际上,这与添加对象的调用是相同的,后者通过POST完成。下面是我代码的核心部分:

HttpURLConnection con = (HttpURLConnection)myurl.openConnection();
con.setRequestMethod("POST");
con.setDoOutput(true);
con.setUseCaches(false);
con.connect();
OutputStreamWriter wr = new OutputStreamWriter(con.getOutputStream());
wr.write(data); // data is the post data to send
wr.flush();

为了发送删除请求,我相应地将请求方法更改为"DELETE"。然而,我收到以下错误:

java.net.ProtocolException: DELETE does not support writing
所以,我的问题是,我该如何从Android发送带有头部数据的DELETE请求?我是否误解了重点 - 你能够在DELETE请求中添加头部数据吗?谢谢。
9个回答

32

有问题的代码行是con.setDoOutput(true);。去掉这行代码可以解决错误。

您可以使用addRequestPropertysetRequestProperty向DELETE请求添加请求头,但无法添加请求正文。


就像在SO上经常看到的那样,唯一正确的答案并没有被选中或得到赞 :( - hgoebl
2
如果我需要使用DELETE方法发送一些JSON怎么办? - Konstantin Konopko
@konopko 或将其作为 URL 的一部分或标头发送。 - Ahmed Alejo

7
这是HttpURLConnection的一个限制,它只适用于旧版本的Android(<=4.4)。
虽然你可以使用HttpClient,但我不建议这样做,因为它是一个旧的库,存在一些问题,并且已经从Android 6中删除
我建议使用像OkHttp这样的新库:
OkHttpClient client = new OkHttpClient();
Request.Builder builder = new Request.Builder()
    .url(getYourURL())
    .delete(RequestBody.create(
        MediaType.parse("application/json; charset=utf-8"), getYourJSONBody()));

Request request = builder.build();

try {
    Response response = client.newCall(request).execute();
    String string = response.body().string();
    // TODO use your response
} catch (IOException e) {
    e.printStackTrace();
}

4

我知道现在有点晚了,但如果有人像我一样在谷歌上搜索并遇到了这个问题,我是这样解决的:

    conn.setRequestProperty("X-HTTP-Method-Override", "DELETE");
    conn.setRequestMethod("POST");

谢谢!这个问题让我很疯狂,但是你的解决方案帮了我。 - XXX
2
只有在您的服务器配置为使用该自定义标头时,此方法才有效。这是常见但不标准的。一些服务器端API框架将查看标头并说:“哦,好的,这实际上是一个删除方法,但他们正在使用POST”。您可以自己编写此行为。 - ADJenks

4

DELETE请求是GET请求的扩展形式。根据Android文档,你不能在DELETE请求的正文中编写内容。HttpUrlConnection会抛出"无法编写协议异常"。

如果您仍然想在正文中编写参数,建议使用OKHttp库

OKHttp文档

如果您想要使用更简单的库,可以尝试SimpleHttpAndroid库

请记住,如果您不在正文中编写任何内容,则删除该行。

conn.setDoOutput(true);

感谢您的阅读,希望这篇文章能对您有所帮助。

4

getOutputStream()仅适用于具有实体的请求,例如POST。在没有实体的请求(例如DELETE)上使用它将引发ProtocolException。相反,您应该使用addHeader()添加标头,而不是调用getOutputStream()。


1
在java.net.HttpURLConnection中我没有看到addHeader()方法,你指的是哪个方法? - androidneil

2

尝试以下方法调用HttpDelete方法,它对我有效,希望它对您也有用

String callHttpDelete(String url){

             try {
                    HttpParams httpParams = new BasicHttpParams();
                    HttpConnectionParams.setConnectionTimeout(httpParams, 15000);
                    HttpConnectionParams.setSoTimeout(httpParams, 15000);

                    //HttpClient httpClient = getNewHttpClient();
                    HttpClient httpClient = new DefaultHttpClient();// httpParams);


                    HttpResponse response = null;    
                    HttpDelete httpDelete = new HttpDelete(url);    
                    response = httpClient.execute(httpDelete); 

                    String sResponse;

                    StringBuilder s = new StringBuilder();

                    while ((sResponse = reader.readLine()) != null) {
                        s = s.append(sResponse);
                    }

                    Log.v(tag, "Yo! Response recvd ["+s.toString()+"]");
                    return s.toString();
                } catch (Exception e){
                    e.printStackTrace();
                }
              return s.toString();
        }

"final_url"是什么?你是不是指"url"?另外,你在哪里向请求写入附加数据?我看不到与问题的任何关联。 - The incredible Jan

0
这是我的Delete请求方法。
简单来说,它是带有额外RequestPropertypost请求。
connection.setRequestProperty("X-HTTP-Method-Override", "DELETE");

以下是完整的方法。

    public void executeDeleteRequest(String stringUrl, JSONObject jsonObject, String reqContentType, String resContentType, int timeout) throws Exception {
    URL url = new URL(stringUrl);
    HttpURLConnection connection = null;
    String urlParameters = jsonObject.toString();
    try {
        connection = (HttpURLConnection) url.openConnection();

        //Setting the request properties and header
        connection.setRequestProperty("X-HTTP-Method-Override", "DELETE");
        connection.setRequestMethod("POST");
        connection.setRequestProperty("User-Agent", USER_AGENT);
        connection.setRequestProperty(CONTENT_TYPE_KEY, reqContentType);
        connection.setRequestProperty(ACCEPT_KEY, resContentType);


        connection.setReadTimeout(timeout);
        connection.setConnectTimeout(defaultTimeOut);

        connection.setUseCaches(false);
        connection.setDoInput(true);
        connection.setDoOutput(true);

        // Send request
        DataOutputStream wr = new DataOutputStream(connection.getOutputStream());
        wr.writeBytes(urlParameters);
        wr.flush();
        wr.close();
        responseCode = connection.getResponseCode();
        // To handle web services which server responds with response code
        // only
        try {
            response = convertStreamToString(connection.getInputStream());
        } catch (Exception e) {
            Log.e(Log.TAG_REST_CLIENT, "Cannot convert the input stream to string for the url= " + stringUrl + ", Code response=" + responseCode + "for the JsonObject: " + jsonObject.toString(), context);
        }
    } catch (
            Exception e
            )

    {
        if (!BController.isInternetAvailable(context)) {
            IntentSender.getInstance().sendIntent(context, Constants.BC_NO_INTERNET_CONNECTION);
            Log.e(Log.TAG_REST_CLIENT, "No internet connection", context);
        }
        Log.e(Log.TAG_REST_CLIENT, "Cannot perform the POST request successfully for the following URL: " + stringUrl + ", Code response=" + responseCode + "for the JsonObject: " + jsonObject.toString(), context);
        throw e;
    } finally{

        if (connection != null) {
            connection.disconnect();
        }
    }

}

希望它有所帮助。


0

2
如上所述,您建议使用哪种addHeader()方法?对我的问题有两个答案似乎都建议使用相同的方法,但除非我漏掉了什么,否则该方法不存在。 - androidneil
看起来你错过了它,看一下HTTPURLConnection的父类URLConnection - hwrdprkns
1
那个方法是addRequestHeader(),它与addHeader()不同。 - androidneil
3
编辑:该方法是addRequestProperty(String field,String newValue)(因此与addHeader()不同)。 此外,它要求我为我的数据赋予一个名称-原始代码在没有任何名称的情况下刷新数据,因此我不确定如何使用它来实现相同的结果。 - androidneil

-7
为了结束这个问题,事实证明不存在支持在HTTP DELETE请求中包含标题数据的方法。
解决方案是客户端修改其API以接受标准的GET请求,指示该操作应该是删除,并包含要删除的项目的ID。
http://clienturl.net/api/delete/id12345

3
这个回答不准确。你可以添加头部数据,只是不能添加正文数据。问题出在调用 setDoOutput(true) 时。 - TalkLittle
6
将方法改为GET是你能做的最糟糕的事情。 - hgoebl
1
将GET请求替换您的DELETE请求绝不是一个好的做法。以后它会导致更多的问题。 - dazito
很容易将自己的回复标记为答案,即使它是不正确的。在你打破投票记录之前,你应该取消标记。干杯! - Ahmed Alejo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接