带正文的 HttpDelete

Posted

技术标签:

【中文标题】带正文的 HttpDelete【英文标题】:HttpDelete with body 【发布时间】:2010-09-22 20:25:55 【问题描述】:

我正在尝试使用 HttpDelete 对象来调用 Web 服务的删除方法。 Web 服务的代码从消息的正文中解析 JSON。但是,我不明白如何将正文添加到 HttpDelete 对象。有没有办法做到这一点?

使用 HttpPut 和 HttpPost,我调用 setEntity 方法并传入我的 JSON。 HttpDelete 似乎没有任何此类方法。

如果无法为 HttpDelete 对象设置主体,请您将我链接到使用 HttpDelete 超类的资源,以便我可以设置方法(删除)并设置主体。我知道这并不理想,但此时我无法更改网络服务。

【问题讨论】:

【参考方案1】:

您是否尝试过如下覆盖HttpEntityEnclosingRequestBase

import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
import java.net.URI;
import org.apache.http.annotation.NotThreadSafe;

@NotThreadSafe
class HttpDeleteWithBody extends HttpEntityEnclosingRequestBase 
    public static final String METHOD_NAME = "DELETE";
    public String getMethod()  return METHOD_NAME; 

    public HttpDeleteWithBody(final String uri) 
        super();
        setURI(URI.create(uri));
    
    public HttpDeleteWithBody(final URI uri) 
        super();
        setURI(uri);
    
    public HttpDeleteWithBody()  super(); 

这将创建一个具有setEntity 方法的HttpDelete-lookalike。我认为抽象类几乎可以为您完成所有工作,所以这可能就是您所需要的。

FWIW,代码基于this source to HttpPost that Google turned up。

【讨论】:

呃!这似乎不适用于 HttpURLConnection。我收到“java.net.ProtocolException:DELETE 不支持写入”。 ***.com/questions/10338615/… 我和 Scott 在一起......我如何使用 HttpURLConnection 做到这一点?我必须重写我的网络代码才能使用 Apache HTTP? 不可能有带有 HttpURLConnection 的正文的 DELETE。我需要它,我最终使用了 HttpClient。【参考方案2】:

按照 Walter Mudnt 的建议,您可以使用此代码。它有效,只是在测试我的 REST 网络服务时成功。

try 
        HttpEntity entity = new StringEntity(jsonArray.toString());
        HttpClient httpClient = new DefaultHttpClient();
        HttpDeleteWithBody httpDeleteWithBody = new HttpDeleteWithBody("http://10.17.1.72:8080/contacts");
        httpDeleteWithBody.setEntity(entity);

        HttpResponse response = httpClient.execute(httpDeleteWithBody);

     catch (UnsupportedEncodingException e) 
        e.printStackTrace();
     catch (ClientProtocolException e) 
        e.printStackTrace();
     catch (IOException e) 
        e.printStackTrace();
    

要访问响应,您只需执行以下操作:response.getStatusLine();

【讨论】:

【参考方案3】:

HTTP DELETE 请求中是否允许正文的问题有不同的解释。例如,请参阅this。在HTTP 1.1 specification 中没有明确禁止。在我看来,您不应该在HTTP DELETE 中使用正文

尽管如此,我认为您应该使用像 mysite/myobject/objectId (shop.com/order/1234) 这样的 URL,其中 objectIdurl 的一部分)是附加信息。作为替代方案,您可以使用 URL 参数mysite/myobject?objectName=table&color=redHTTP DELETE 请求中向服务器发送附加信息。以“?”开头的部分是 urlencoded 参数分隔 dy '&'。

如果您想发送更复杂的信息,您可以将数据转换为关于 DataContractJsonSerializer 或 javascriptSerializer 的 JSON,然后将转换后的数据(我稍后命名为 myJsonData 的字符串)也作为参数发送: mysite/myobject?objectInfo=myJsonData.

如果您需要在 HTTP DELETE 请求中发送过多的附加数据,从而导致 URL 长度出现问题,那么您最好更改应用程序的设计。

已更新:如果您确实希望通过 HTTP DELETE 发送一些正文,您可以这样做,例如如下所示

// somewhere above add: using System.Net; and using System.IO;

WebClient myWebClient = new WebClient ();

// 1) version: do simple request    
string t= myWebClient.UploadString ("http://www.examples.com/", "DELETE", "bla bla");
// will be send following:
//
// DELETE http://www.examples.com/ HTTP/1.1
// Host: www.examples.com
// Content-Length: 7
// Expect: 100-continue
// Connection: Keep-Alive
//
//bla bla

// 2) version do complex request    
Stream stream = myWebClient.OpenWrite ("http://www.examples.com/", "DELETE");

string postData = "bla bla";
byte[] myDataAsBytes = Encoding.UTF8.GetBytes (postData);
stream.Write (myDataAsBytes, 0, myDataAsBytes.Length);
stream.Close (); // it send the data
// will be send following:
// 
// DELETE http://www.examples.com/ HTTP/1.1
// Host: www.examples.com
// Content-Length: 7
// Expect: 100-continue
// 
// bla bla

// 3) version
// create web request 
HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create ("http://www.examples.com/");
webRequest.Method = "DELETE";
webRequest.ServicePoint.Expect100Continue = false;

// post data 
Stream requestStream = webRequest.GetRequestStream ();
StreamWriter requestWriter = new StreamWriter (requestStream);
requestWriter.Write (postData);
requestWriter.Close ();

//wait for server response 
HttpWebResponse response = (HttpWebResponse)webRequest.GetResponse ();
// send following:
// DELETE http://www.examples.com/ HTTP/1.1
// Host: www.examples.com
// Content-Length: 7
// Connection: Keep-Alive
// 
// bla bla

完整的代码可能会稍微复杂一些,但是这个已经可以工作了。尽管如此,我还是要说,Web Service 需要的 HTTP DELETE 请求正文中的数据设计不佳。

【讨论】:

-1。提问者说的很清楚,他不能改变网络服务,而且他可能也没有设计它。由于这篇文章中的每条建议都涉及更改不受提问者控制的代码,因此在手头的情况下完全没有帮助。 对于它的价值,我原则上不同意你的观点;需要带有主体的 DELETE 方法的 Web 服务可能设计不佳。尽管如此,询问如何与设计不佳且可能不符合标准的 Web 服务交互是合理的,这就是我对这个问题的解释。 @Walter Mundt:如果一个确实需要在 HTTP DELETE 中发送正文,我添加了一个示例,其中一种可能的方法是。 我能问一下为什么有一个带有删除方法的主体不是一个好主意吗?仅仅是因为人们通常不这样做吗?当然可以;那么这是一个坏主意的原因是什么? (我没有不同意。我只是在询问。我是网络服务的新手) @Andrew:大多数HTTP库类等的实现都认为DELETE应该没有body。在这种情况下,必须有一个 非常好的 理由来设计具有此功能的 wen 服务的实现。大多数情况下,在 RESTful 服务中不使用 HTTP DELETE。在 REST 中,url 应该标识资源,因此 HTTP DELETE 包含有关应该在 在 URL 中删除的对象的所有信息。不禁止使用带参数的 HTTP GET 来更改资源或使用 HTTP PUT 来删除资源,但这会是一种糟糕的风格(糟糕的设计)。【参考方案4】:

使用这个,

class MyDelete extends HttpPost
    public MyDelete(String url)
        super(url);
    
    @Override
    public String getMethod() 
        return "DELETE";
    

【讨论】:

【参考方案5】:

改造中

import okhttp3.Request;

private final class ApiInterceptor implements Interceptor 

    @Override
    public Response intercept(Chain chain) throws IOException 
        Request oldRequest = chain.request();
        Request.Builder builder = oldRequest.newBuilder();
        if(condition) 
            return chain.proceed(builder.build().newBuilder().delete(builder.build().body()).build());
        
        return chain.proceed(builder.build());
    

您必须通过某些东西触发条件,并且可能必须对 url/header/body 进行一些过滤以删除触发器,

除非删除 url/body/header 足够独特,不会与 post 或 get 请求发生冲突。

【讨论】:

以上是关于带正文的 HttpDelete的主要内容,如果未能解决你的问题,请参考以下文章

使用Retrofit(Okhttp)时如何从android studio中的log cat复制请求正文,标头(不带标签)?

在调用gmail api发送带附件的电子邮件(multipart)时,请求的正文如何?

[Java] JavaMail 发送带图片的 html 格式的邮件

如何利用linux 的mail命令发送带格式(比如正文的字体,大小等)的邮件呢?

没有附件的正文上的phpMailer图像

使用 PHP 的邮件正文中的 MIME 信息