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

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

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

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

【问题讨论】:

    标签: android httpclient webservice-client http-delete


    【解决方案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 不支持写入”。 stackoverflow.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 '&'。

      如果您想发送更复杂的信息,您可以将数据转换为关于 DataContractJsonSerializerJavaScriptSerializer 的 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 请求发生冲突。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-02-01
          • 1970-01-01
          • 2023-01-01
          相关资源
          最近更新 更多