如何从Java客户端发出返回空响应的HEAD请求?

huangapple go评论89阅读模式
英文:

How to call a HEAD request which returns an empty response from JAVA client?

问题

我试图调用一个API,该API返回100作为响应代码并且没有响应内容。

import org.apache.http.client.methods.HttpHead;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;

import java.net.URI;

public class SampleController {

    public static void main(String[] args) throws Exception {

        try {
            String urlStr = "http://localhost:8080/headrequest";
            HttpHead request = new HttpHead(new URI(urlStr));
            request.addHeader("Expect", "100-continue");

            CloseableHttpClient client = HttpClients.createDefault();
            client.execute(request);
        } catch (Exception e) {
            System.out.println("Exception: " + e.getMessage());
            throw e;
        }
    }
}

以下是错误信息:

INFO: I/O exception (org.apache.http.NoHttpResponseException) caught when processing request to {}->http://localhost:8080: The target server failed to respond
Aug 19, 2020 3:36:26 PM org.apache.http.impl.execchain.RetryExec execute
INFO: Retrying request to {}->http://localhost:8080
Aug 19, 2020 3:36:26 PM org.apache.http.impl.execchain.RetryExec execute
INFO: I/O exception (org.apache.http.NoHttpResponseException) caught when processing request to {}->http://localhost:8080: The target server failed to respond
Aug 19, 2020 3:36:26 PM org.apache.http.impl.execchain.RetryExec execute
INFO: Retrying request to {}->http://localhost:8080
Aug 19, 2020 3:36:26 PM org.apache.http.impl.execchain.RetryExec execute
INFO: I/O exception (org.apache.http.NoHttpResponseException) caught when processing request to {}->http://localhost:8080: The target server failed to respond
Aug 19, 2020 3:36:26 PM org.apache.http.impl.execchain.RetryExec execute
INFO: Retrying request to {}->http://localhost:8080
Exception in thread "main" org.apache.http.NoHttpResponseException: localhost:8080 failed to respond
Exception: localhost:8080 failed to respond
    at org.apache.http.impl.conn.DefaultHttpResponseParser.parseHead(DefaultHttpResponseParser.java:141)
    at org.apache.http.impl.conn.DefaultHttpResponseParser.parseHead(DefaultHttpResponseParser.java:56)
    at org.apache.http.impl.io.AbstractMessageParser.parse(AbstractMessageParser.java:259)
    at org.apache.http.impl.DefaultBHttpClientConnection.receiveResponseHeader(DefaultBHttpClientConnection.java:163)
    at org.apache.http.impl.conn.CPoolProxy.receiveResponseHeader(CPoolProxy.java:157)
    at org.apache.http.protocol.HttpRequestExecutor.doReceiveResponse(HttpRequestExecutor.java:273)
    at org.apache.http.protocol.HttpRequestExecutor.execute(HttpRequestExecutor.java:125)
    at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:272)
    at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:186)
    at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:89)
    at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:110)
    at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:185)
    at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:83)
    at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:108)
    at com.application.controller.SampleController.main(SampleController.java:20)

但从服务器的访问日志中,我可以确认该API已被执行并且服务器返回了一个100的响应代码。

"HEAD /headrequest HTTP/1.1" 100

因此,从上面的错误信息中我了解到,Apache HttpClient没有配置为在服务器发送响应代码 100 后终止连接,仍然期望服务器发送响应。

我的问题是,是否有任何Java库可以处理在收到100响应后终止HEAD请求。

我尝试使用HttpURLConnection

private static void testing() throws Exception {
    HttpURLConnection urlConn = null;

    try {
        String urlStr = "http://localhost:8080/headrequest";

        URL url = new URL(urlStr);
        urlConn = (HttpURLConnection) url.openConnection();
        urlConn.setRequestMethod("HEAD");

        urlConn.setRequestProperty("Expect", "100-continue");

        if (urlConn.getResponseCode() != 100) {
            System.out.println("Miss match in the response: " + urlConn.getResponseCode());
        }

    } catch (Exception e) {
        System.out.println("Exception: " + e.getMessage());
        throw e;
    }
}

以下是错误响应:

Exception: Unexpected end of file from server
Exception in thread "main" java.net.SocketException: Unexpected end of file from server
    at sun.net.www.http.HttpClient.parseHTTPHeader(HttpClient.java:851)
    at sun.net.www.http.HttpClient.parseHTTPHeader(HttpClient.java:877)
    at sun.net.www.http.HttpClient.parseHTTPHeader(HttpClient.java:877)
    at sun.net.www.http.HttpClient.parseHTTP(HttpClient.java:678)
    at sun.net.www.http.HttpClient.parseHTTPHeader(HttpClient.java:848)
    at sun.net.www.http.HttpClient.parseHTTPHeader(HttpClient.java:877)
    at sun.net.www.http.HttpClient.parseHTTPHeader(HttpClient.java:877)
    at sun.net.www.http.HttpClient.parseHTTP(HttpClient.java:678)
    at sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1593)
    at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1498)
    at java.net.HttpURLConnection.getResponseCode(HttpURLConnection.java:480)
    at com.application.controller.SampleController.testing(SampleController.java:44)
    at com.application.controller.SampleController.main(SampleController.java:28)
英文:

I am trying to call a API which returns 100 as response code and empty response.

import org.apache.http.client.methods.HttpHead;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;

import java.net.URI;

public class SampleController {

    public static void main(String[] args) throws Exception {

        try {
            String urlStr = "http://localhost:8080/headrequest";
            HttpHead request = new HttpHead(new URI(urlStr));
            request.addHeader("Expect", "100-continue");

            CloseableHttpClient client = HttpClients.createDefault();
            client.execute(request);
        } catch (Exception e) {
            System.out.println("Exception: " + e.getMessage());
            throw e;
        }
    }
}

Below is the error:

INFO: I/O exception (org.apache.http.NoHttpResponseException) caught when processing request to {}->http://localhost:8080: The target server failed to respond
Aug 19, 2020 3:36:26 PM org.apache.http.impl.execchain.RetryExec execute
INFO: Retrying request to {}->http://localhost:8080
Aug 19, 2020 3:36:26 PM org.apache.http.impl.execchain.RetryExec execute
INFO: I/O exception (org.apache.http.NoHttpResponseException) caught when processing request to {}->http://localhost:8080: The target server failed to respond
Aug 19, 2020 3:36:26 PM org.apache.http.impl.execchain.RetryExec execute
INFO: Retrying request to {}->http://localhost:8080
Aug 19, 2020 3:36:26 PM org.apache.http.impl.execchain.RetryExec execute
INFO: I/O exception (org.apache.http.NoHttpResponseException) caught when processing request to {}->http://localhost:8080: The target server failed to respond
Aug 19, 2020 3:36:26 PM org.apache.http.impl.execchain.RetryExec execute
INFO: Retrying request to {}->http://localhost:8080
Exception in thread "main" org.apache.http.NoHttpResponseException: localhost:8080 failed to respond
Exception: localhost:8080 failed to respond
	at org.apache.http.impl.conn.DefaultHttpResponseParser.parseHead(DefaultHttpResponseParser.java:141)
	at org.apache.http.impl.conn.DefaultHttpResponseParser.parseHead(DefaultHttpResponseParser.java:56)
	at org.apache.http.impl.io.AbstractMessageParser.parse(AbstractMessageParser.java:259)
	at org.apache.http.impl.DefaultBHttpClientConnection.receiveResponseHeader(DefaultBHttpClientConnection.java:163)
	at org.apache.http.impl.conn.CPoolProxy.receiveResponseHeader(CPoolProxy.java:157)
	at org.apache.http.protocol.HttpRequestExecutor.doReceiveResponse(HttpRequestExecutor.java:273)
	at org.apache.http.protocol.HttpRequestExecutor.execute(HttpRequestExecutor.java:125)
	at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:272)
	at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:186)
	at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:89)
	at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:110)
	at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:185)
	at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:83)
	at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:108)
	at com.application.controller.SampleController.main(SampleController.java:20)

But from the servers access logs. I can confirm that the API has executed and the server returned a 100 response code.

"HEAD /headrequest HTTP/1.1" 100

So, from the above error I understand that the apaches HttpClinet is not configured to terminate connection once the server sends response code 100 and still expecting the server to send response.

My question here is, are there any java libs that handle the termination of HEAD request once it receives 100.

I did try googling this but was unsuccessful to determine any solution 如何从Java客户端发出返回空响应的HEAD请求?

Edit 1: I tried with HttpURLConnection

private static void testing() throws Exception {
        HttpURLConnection urlConn = null;

        try {
            String urlStr = "http://localhost:8080/headrequest";

            URL url = new URL(urlStr);
            urlConn = (HttpURLConnection) url.openConnection();
            urlConn.setRequestMethod("HEAD");

            
            urlConn.setRequestProperty("Expect", "100-continue");

            if (urlConn.getResponseCode() != 100) {
                System.out.println("Miss match in the response: " + urlConn.getResponseCode());
            }

        } catch (Exception e) {
            System.out.println("Exception: " + e.getMessage());
            throw e;
        }
    }

Below is the error response:

Exception: Unexpected end of file from server
Exception in thread "main" java.net.SocketException: Unexpected end of file from server
	at sun.net.www.http.HttpClient.parseHTTPHeader(HttpClient.java:851)
	at sun.net.www.http.HttpClient.parseHTTPHeader(HttpClient.java:877)
	at sun.net.www.http.HttpClient.parseHTTPHeader(HttpClient.java:877)
	at sun.net.www.http.HttpClient.parseHTTP(HttpClient.java:678)
	at sun.net.www.http.HttpClient.parseHTTPHeader(HttpClient.java:848)
	at sun.net.www.http.HttpClient.parseHTTPHeader(HttpClient.java:877)
	at sun.net.www.http.HttpClient.parseHTTPHeader(HttpClient.java:877)
	at sun.net.www.http.HttpClient.parseHTTP(HttpClient.java:678)
	at sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1593)
	at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1498)
	at java.net.HttpURLConnection.getResponseCode(HttpURLConnection.java:480)
	at com.application.controller.SampleController.testing(SampleController.java:44)
	at com.application.controller.SampleController.main(SampleController.java:28)

答案1

得分: 2

RFC7231中提到:

> 在不包含消息主体的请求中,客户端不得生成100-continue预期。

因此,很可能是appacheclient期望在收到100响应后发送消息主体,但由于连接关闭而引发异常。

如果不强制使用apacheclient,以下简单的代码将仅读取带有100状态代码的响应行并关闭连接。

import java.io.*;
import java.net.*;

class Requestor
{
    public static void main(String args[])
    {
        Socket s;
        BufferedReader br;
        BufferedWriter bw;
        String a;
        String response;
        try{
            s = new Socket("localhost", 8080);
            br = new BufferedReader(new InputStreamReader(new BufferedInputStream(s.getInputStream())));
            bw = new BufferedWriter(new OutputStreamWriter(new BufferedOutputStream(s.getOutputStream())));

            bw.write("HEAD /headrequest HTTP/1.1");
            bw.newLine();
            bw.newLine();
            bw.flush();
            response = "";

            a = br.readLine();
            System.out.println(a);

            s.close();
        }
        catch(Exception e)
        {
            System.out.println(e);
        }
    }
}
英文:

RFC7231 says

> A client MUST NOT generate a 100-continue expectation in a request
that does not include a message body.

Hence its probably appacheclient which expects to send message body once 100 response received, throws exception as the connection closed.

If its not mandatory to use apacheclient, below simple code will read just the response line with 100 status code and close the connection.

import java.io.*;
import java.net.*;
class Requestor
{
    public static void main(String args[])
    {
        Socket s;
        BufferedReader br;
        BufferedWriter bw;
        String a;
        String response;
        try{
        s=new Socket("localhost",8080);
        br=new BufferedReader(new InputStreamReader(new BufferedInputStream(s.getInputStream())));
        bw=new BufferedWriter(new OutputStreamWriter(new BufferedOutputStream(s.getOutputStream())));

        bw.write("HEAD /headrequest HTTP/1.1");
        bw.newLine();
        bw.newLine();
        bw.flush();
        response="";
        
        a=br.readLine();
        System.out.println(a);
        
        s.close();
        
        }
        catch(Exception e)
        {
            System.out.println(e);
        }
    }
}

huangapple
  • 本文由 发表于 2020年8月19日 18:24:55
  • 转载请务必保留本文链接:https://go.coder-hub.com/63484948.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定