วิธีตั้งค่าการหมดเวลา HttpResponse สำหรับ Android ใน Java


333

ฉันได้สร้างฟังก์ชั่นต่อไปนี้เพื่อตรวจสอบสถานะการเชื่อมต่อ:

private void checkConnectionStatus() {
    HttpClient httpClient = new DefaultHttpClient();

    try {
      String url = "http://xxx.xxx.xxx.xxx:8000/GaitLink/"
                   + strSessionString + "/ConnectionStatus";
      Log.d("phobos", "performing get " + url);
      HttpGet method = new HttpGet(new URI(url));
      HttpResponse response = httpClient.execute(method);

      if (response != null) {
        String result = getResponse(response.getEntity());
        ...

เมื่อฉันปิดเซิร์ฟเวอร์สำหรับการทดสอบการดำเนินการรอเป็นเวลานานที่บรรทัด

HttpResponse response = httpClient.execute(method);

ไม่มีใครรู้วิธีการตั้งค่าการหมดเวลาเพื่อหลีกเลี่ยงการรอนานเกินไป?

ขอบคุณ!

คำตอบ:


625

ในตัวอย่างของฉันมีการตั้งค่าการหมดเวลาสองครั้ง การเชื่อมต่อหมดเวลาพ่นและหมดเวลาซ็อกเก็ตjava.net.SocketTimeoutException: Socket is not connectedjava.net.SocketTimeoutException: The operation timed out

HttpGet httpGet = new HttpGet(url);
HttpParams httpParameters = new BasicHttpParams();
// Set the timeout in milliseconds until a connection is established.
// The default value is zero, that means the timeout is not used. 
int timeoutConnection = 3000;
HttpConnectionParams.setConnectionTimeout(httpParameters, timeoutConnection);
// Set the default socket timeout (SO_TIMEOUT) 
// in milliseconds which is the timeout for waiting for data.
int timeoutSocket = 5000;
HttpConnectionParams.setSoTimeout(httpParameters, timeoutSocket);

DefaultHttpClient httpClient = new DefaultHttpClient(httpParameters);
HttpResponse response = httpClient.execute(httpGet);

หากคุณต้องการตั้งค่าพารามิเตอร์ของใด ๆ HttpClient ที่มีอยู่ (เช่น DefaultHttpClient หรือ AndroidHttpClient) คุณสามารถใช้ฟังก์ชั่นsetParams ()

httpClient.setParams(httpParameters);

1
@Thomas: ฉันได้แก้ไขคำตอบของฉันด้วยโซลูชันสำหรับ usecase ของคุณแล้ว
kuester2000

3
HttpResponse จะส่งคืนอะไรถ้าการเชื่อมต่อหมดเวลา ในขณะที่คำขอ HTTP ของฉันถูกสร้างขึ้นฉันจะตรวจสอบรหัสสถานะเมื่อมีการโทรกลับ แต่ฉันได้รับ NullPointerException เมื่อตรวจสอบรหัสนี้หากการโทรหมดเวลา ... โดยทั่วไปฉันจะจัดการสถานการณ์อย่างไรเมื่อมีการโทร หมดเวลาหรือไม่ (ฉันใช้รหัสที่คล้ายกันมากกับคำตอบของคุณ)
ทิม

10
@jellyfish - แม้จะมีเอกสารประกอบ AndroidHttpClient ไม่ขยาย DefaultHttpClient ค่อนข้างจะใช้ HttpClient คุณจะต้องใช้ DefaultHttpClient เพื่อให้สามารถใช้วิธี setParams (HttpParams) ได้
Ted Hopp

3
เฮ้พวกแฮงค์สำหรับคำตอบที่ยอดเยี่ยม แต่ฉันต้องการแสดงขนมปังให้กับผู้ใช้เมื่อหมดเวลาเชื่อมต่อ ... วิธีใดที่ฉันสามารถตรวจพบได้เมื่อการเชื่อมต่อหมดเวลา
Arnab Chakraborty

2
ใช้งานไม่ได้ ฉันทดสอบกับ Sony และ Moto ของพวกเขาพวกเขาทั้งหมดถูกซุก
thecr0w

13

วิธีตั้งค่าบนไคลเอนต์:

AndroidHttpClient client = AndroidHttpClient.newInstance("Awesome User Agent V/1.0");
HttpConnectionParams.setConnectionTimeout(client.getParams(), 3000);
HttpConnectionParams.setSoTimeout(client.getParams(), 5000);

ฉันใช้สิ่งนี้ได้สำเร็จบน JellyBean แต่ควรใช้กับแพลตฟอร์มเก่า ...

HTH


ความสัมพันธ์กับ HttpClient คืออะไร
Sazzad Hissain Khan

8

หากคุณกำลังใช้ห้องสมุดลูกค้า httpของจาการ์ตาคุณสามารถทำสิ่งต่อไปนี้:

        HttpClient client = new HttpClient();
        client.getParams().setParameter(HttpClientParams.CONNECTION_MANAGER_TIMEOUT, new Long(5000));
        client.getParams().setParameter(HttpClientParams.SO_TIMEOUT, new Integer(5000));
        GetMethod method = new GetMethod("http://www.yoururl.com");
        method.getParams().setParameter(HttpMethodParams.SO_TIMEOUT, new Integer(5000));
        method.getParams().setParameter(HttpMethodParams.RETRY_HANDLER,
        int statuscode = client.executeMethod(method);

5
HttpClientParams.CONNECTION_MANAGER_TIMEOUT ไม่เป็นที่รู้จัก
Tawani

คุณควรใช้ client.getParams (). setIntParameter (.. ) สำหรับ params * _TIMEOUT
loafoe

หาได้อย่างไร อุปกรณ์เชื่อมต่อกับ wifi แต่ไม่ใช่ข้อมูลที่ใช้งานจริงผ่าน wifi
พระพิฆเนศ Katikar

7

หากคุณใช้ไคลเอนต์ http เริ่มต้นต่อไปนี้เป็นวิธีใช้โดยใช้พารามิเตอร์ http เริ่มต้น:

HttpClient client = new DefaultHttpClient();
HttpParams params = client.getParams();
HttpConnectionParams.setConnectionTimeout(params, 3000);
HttpConnectionParams.setSoTimeout(params, 3000);

เครดิตดั้งเดิมไปที่http://www.jayway.com/2009/03/17/configuring-timeout-with-apache-httpclient-40/


5

สำหรับผู้ที่กล่าวว่าคำตอบของ @ kuester2000 ใช้งานไม่ได้โปรดทราบว่าการร้องขอ HTTP ก่อนอื่นให้ลองค้นหาโฮสต์ IP ที่มีการร้องขอ DNS จากนั้นทำการร้องขอ HTTP จริงไปยังเซิร์ฟเวอร์ดังนั้นคุณอาจต้องตั้งค่า หมดเวลาสำหรับคำขอ DNS

หากรหัสของคุณทำงานโดยไม่มีการหมดเวลาสำหรับคำขอ DNS นั่นเป็นเพราะคุณสามารถเข้าถึงเซิร์ฟเวอร์ DNS หรือคุณกำลังกดแคช Android DNS โดยวิธีการที่คุณสามารถล้างแคชนี้โดยการรีสตาร์ทอุปกรณ์

รหัสนี้ขยายคำตอบดั้งเดิมเพื่อรวมการค้นหา DNS ด้วยตนเองด้วยการหมดเวลาที่กำหนดเอง:

//Our objective
String sURL = "http://www.google.com/";
int DNSTimeout = 1000;
int HTTPTimeout = 2000;

//Get the IP of the Host
URL url= null;
try {
     url = ResolveHostIP(sURL,DNSTimeout);
} catch (MalformedURLException e) {
    Log.d("INFO",e.getMessage());
}

if(url==null){
    //the DNS lookup timed out or failed.
}

//Build the request parameters
HttpParams params = new BasicHttpParams();
HttpConnectionParams.setConnectionTimeout(params, HTTPTimeout);
HttpConnectionParams.setSoTimeout(params, HTTPTimeout);

DefaultHttpClient client = new DefaultHttpClient(params);

HttpResponse httpResponse;
String text;
try {
    //Execute the request (here it blocks the execution until finished or a timeout)
    httpResponse = client.execute(new HttpGet(url.toString()));
} catch (IOException e) {
    //If you hit this probably the connection timed out
    Log.d("INFO",e.getMessage());
}

//If you get here everything went OK so check response code, body or whatever

วิธีที่ใช้:

//Run the DNS lookup manually to be able to time it out.
public static URL ResolveHostIP (String sURL, int timeout) throws MalformedURLException {
    URL url= new URL(sURL);
    //Resolve the host IP on a new thread
    DNSResolver dnsRes = new DNSResolver(url.getHost());
    Thread t = new Thread(dnsRes);
    t.start();
    //Join the thread for some time
    try {
        t.join(timeout);
    } catch (InterruptedException e) {
        Log.d("DEBUG", "DNS lookup interrupted");
        return null;
    }

    //get the IP of the host
    InetAddress inetAddr = dnsRes.get();
    if(inetAddr==null) {
        Log.d("DEBUG", "DNS timed out.");
        return null;
    }

    //rebuild the URL with the IP and return it
    Log.d("DEBUG", "DNS solved.");
    return new URL(url.getProtocol(),inetAddr.getHostAddress(),url.getPort(),url.getFile());
}   

คลาสนี้มาจากบล็อกโพสต์นี้ ไปและตรวจสอบข้อสังเกตว่าคุณจะใช้มัน

public static class DNSResolver implements Runnable {
    private String domain;
    private InetAddress inetAddr;

    public DNSResolver(String domain) {
        this.domain = domain;
    }

    public void run() {
        try {
            InetAddress addr = InetAddress.getByName(domain);
            set(addr);
        } catch (UnknownHostException e) {
        }
    }

    public synchronized void set(InetAddress inetAddr) {
        this.inetAddr = inetAddr;
    }
    public synchronized InetAddress get() {
        return inetAddr;
    }
}

1
HttpParams httpParameters = new BasicHttpParams();
            HttpProtocolParams.setVersion(httpParameters, HttpVersion.HTTP_1_1);
            HttpProtocolParams.setContentCharset(httpParameters,
                    HTTP.DEFAULT_CONTENT_CHARSET);
            HttpProtocolParams.setUseExpectContinue(httpParameters, true);

            // Set the timeout in milliseconds until a connection is
            // established.
            // The default value is zero, that means the timeout is not used.
            int timeoutConnection = 35 * 1000;
            HttpConnectionParams.setConnectionTimeout(httpParameters,
                    timeoutConnection);
            // Set the default socket timeout (SO_TIMEOUT)
            // in milliseconds which is the timeout for waiting for data.
            int timeoutSocket = 30 * 1000;
            HttpConnectionParams.setSoTimeout(httpParameters, timeoutSocket);

ไม่สมบูรณ์. อะไรคือความสัมพันธ์กับ HttpClient
Sazzad Hissain Khan

1

คุณสามารถสร้างอินสแตนซ์ HttpClient ได้ด้วย Httpclient-android-4.3.5 มันสามารถทำงานได้ดี

 SSLContext sslContext = SSLContexts.createSystemDefault();
        SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
                sslContext,
                SSLConnectionSocketFactory.STRICT_HOSTNAME_VERIFIER);
                RequestConfig.Builder requestConfigBuilder = RequestConfig.custom().setCircularRedirectsAllowed(false).setConnectionRequestTimeout(30*1000).setConnectTimeout(30 * 1000).setMaxRedirects(10).setSocketTimeout(60 * 1000);
        CloseableHttpClient hc = HttpClients.custom().setSSLSocketFactory(sslsf).setDefaultRequestConfig(requestConfigBuilder.build()).build();

1

ตัวเลือกคือการใช้OkHttpไคลเอ็นต์จาก Square

เพิ่มการพึ่งพาไลบรารี

ใน build.gradle ให้รวมบรรทัดนี้:

compile 'com.squareup.okhttp:okhttp:x.x.x'

x.x.xรุ่นไลบรารี่ที่ต้องการอยู่ที่ไหน

ตั้งค่าไคลเอนต์

ตัวอย่างเช่นหากคุณต้องการตั้งค่าการหมดเวลา 60 วินาทีให้ทำดังนี้:

final OkHttpClient okHttpClient = new OkHttpClient();
okHttpClient.setReadTimeout(60, TimeUnit.SECONDS);
okHttpClient.setConnectTimeout(60, TimeUnit.SECONDS);

PS: ถ้า minSdkVersion ของคุณสูงกว่า 8 TimeUnit.MINUTESคุณสามารถใช้ ดังนั้นคุณสามารถใช้:

okHttpClient.setReadTimeout(1, TimeUnit.MINUTES);
okHttpClient.setConnectTimeout(1, TimeUnit.MINUTES);

สำหรับรายละเอียดเพิ่มเติมเกี่ยวกับหน่วยให้ดูTIMEUNIT


ในเวอร์ชันปัจจุบันของ OkHttp จะต้องตั้งค่าการหมดเวลาให้แตกต่างกัน: https://github.com/square/okhttp/blob/master/samples/guide/src/main/java/okhttp3/recipes/ConfigureTimeouts.java
thijsonline

1

หากคุณใช้งานHttpURLConnectionโทรsetConnectTimeout()ตามที่อธิบายไว้ที่นี่ :

URL url = new URL(myurl);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(CONNECT_TIMEOUT);

คำอธิบายเป็นเหมือนการหมดเวลาในการสร้างการเชื่อมต่อแทนที่จะเป็นคำขอ http หรือไม่
2499800

0
public boolean isInternetWorking(){
    try {
        int timeOut = 5000;
        Socket socket = new Socket();
        SocketAddress socketAddress = new InetSocketAddress("8.8.8.8",53);
        socket.connect(socketAddress,timeOut);
        socket.close();
        return true;
    } catch (IOException e) {
        //silent
    }
    return false;
}

เซิร์ฟเวอร์ใดที่เป็นตัวแทน "8.8.8.8", 53
Junaed
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.