การตั้งค่าการหมดเวลาการเชื่อมต่อ HttpURL


123

ฉันต้องการส่งคืนเท็จหาก URL ใช้เวลามากกว่า 5 วินาทีในการเชื่อมต่อ - เป็นไปได้อย่างไรเมื่อใช้ Java นี่คือรหัสที่ฉันใช้เพื่อตรวจสอบว่า URL ถูกต้องหรือไม่

HttpURLConnection.setFollowRedirects(false);
HttpURLConnection con = (HttpURLConnection) new URL(url).openConnection();
con.setRequestMethod("HEAD");
return (con.getResponseCode() == HttpURLConnection.HTTP_OK);

คำตอบ:


201

HttpURLConnectionมีเมธอดsetConnectTimeout

เพียงตั้งค่าระยะหมดเวลาเป็น 5,000 มิลลิวินาทีจากนั้นจึงจับ java.net.SocketTimeoutException

รหัสของคุณควรมีลักษณะดังนี้:


try {
   HttpURLConnection.setFollowRedirects(false);
   HttpURLConnection con = (HttpURLConnection) new URL(url).openConnection();
   con.setRequestMethod("HEAD");

   con.setConnectTimeout(5000); //set timeout to 5 seconds

   return (con.getResponseCode() == HttpURLConnection.HTTP_OK);
} catch (java.net.SocketTimeoutException e) {
   return false;
} catch (java.io.IOException e) {
   return false;
}



3
ฉันตั้งค่าเป็น 10 นาที อย่างไรก็ตามมันทำให้ฉันขว้างjava.net.ConnectException: Connection timed out: connectก่อน 2 นาทีด้วยซ้ำ คุณรู้หรือไม่ว่าอะไรเป็นสาเหตุของปัญหา?
Pacerier

5
SocketTimeoutException เป็นคลาสย่อยของ IOException หากทั้งสองบล็อกจับทำสิ่งเดียวกันคุณก็สามารถจับ IOException ได้
spaaarky21

2
@ spaaarky21 ถูกต้อง. อย่างไรก็ตามหากคุณกำลังสร้าง UI และต้องการแจ้งให้ผู้ใช้ของคุณทราบว่าการหมดเวลาเกิดขึ้นคุณต้องตรวจจับ SocketTimeoutException ก่อน IOException หากไม่เป็นเช่นนั้นจะไม่สามารถเข้าถึงได้
นาฬิกา

3
หมายเหตุ !!! คุณต้องโทรsetConnectTimeoutก่อนวิธีการใด ๆ ที่เชื่อมต่อโดยปริยาย (โดยทั่วไปคือวิธีการทั้งหมดที่ส่ง IllegalStateException หากเชื่อมต่อแล้ว) ทำให้ setConnectTimeout (readTimeout) เป็นวิธีแรกที่เรียกว่า
Adam Gent

4
มันไม่ได้ผลสำหรับฉัน แต่หลังจากเพิ่มcon.setReadTimeout()แล้วมันก็ทำงานตามที่คาดไว้
Paulo

115

คุณสามารถกำหนดระยะหมดเวลาเช่นนี้

con.setConnectTimeout(connectTimeout);
con.setReadTimeout(socketTimeout);

2
ค่าหมดเวลาสูงสุดที่เราระบุได้คือเท่าไร?
Pacerier

7
@Pacerier เอกสารนี้ไม่ได้ระบุอย่างชัดเจน จะโยน IllegalArgumentException ถ้าค่าเป็นลบ (ค่า 0 จะหมายถึงรอไปเรื่อย ๆ ) เนื่องจากการหมดเวลาเป็น int 32 บิตที่ไม่ได้ลงนามฉันจึงเดาว่าการหมดเวลาสูงสุดจะอยู่ที่ประมาณ 49 วัน (แม้ว่าฉันจะสงสัยอย่างจริงจังว่าค่านี้จะเป็นประโยชน์กับทุกคนก็ตาม)
Jay Sidri

1

หากการเชื่อมต่อ HTTP ไม่หมดเวลาคุณสามารถใช้ตัวตรวจสอบการหมดเวลาในเธรดพื้นหลังได้เอง (AsyncTask, Service ฯลฯ ) คลาสต่อไปนี้เป็นตัวอย่างสำหรับ Customize AsyncTask ซึ่งหมดเวลาหลังจากช่วงเวลาหนึ่ง

public abstract class AsyncTaskWithTimer<Params, Progress, Result> extends
    AsyncTask<Params, Progress, Result> {

private static final int HTTP_REQUEST_TIMEOUT = 30000;

@Override
protected Result doInBackground(Params... params) {
    createTimeoutListener();
    return doInBackgroundImpl(params);
}

private void createTimeoutListener() {
    Thread timeout = new Thread() {
        public void run() {
            Looper.prepare();

            final Handler handler = new Handler();
            handler.postDelayed(new Runnable() {
                @Override
                public void run() {

                    if (AsyncTaskWithTimer.this != null
                            && AsyncTaskWithTimer.this.getStatus() != Status.FINISHED)
                        AsyncTaskWithTimer.this.cancel(true);
                    handler.removeCallbacks(this);
                    Looper.myLooper().quit();
                }
            }, HTTP_REQUEST_TIMEOUT);

            Looper.loop();
        }
    };
    timeout.start();
}

abstract protected Result doInBackgroundImpl(Params... params);
}

ตัวอย่างสำหรับสิ่งนี้

public class AsyncTaskWithTimerSample extends AsyncTaskWithTimer<Void, Void, Void> {

    @Override
    protected void onCancelled(Void void) {
        Log.d(TAG, "Async Task onCancelled With Result");
        super.onCancelled(result);
    }

    @Override
    protected void onCancelled() {
        Log.d(TAG, "Async Task onCancelled");
        super.onCancelled();
    }

    @Override
    protected Void doInBackgroundImpl(Void... params) {
        // Do background work
        return null;
    };
 }

ไม่จำเป็นอย่างยิ่งที่จะต้องสร้างเธรด looper ใหม่เพียงเพื่อกำหนดเวลาการโทรเพื่อยกเลิก () คุณสามารถทำได้จากเธรดหลักในonPreExecute(). นอกจากนี้หากคุณยกเลิกงานด้วยตนเองคุณควรยกเลิกการโทรตามกำหนดเวลาด้วยเพื่อหลีกเลี่ยงการรั่วไหล
BladeCoder

จุดที่นี่คือการยกเลิก AsyncTask ตรงกลาง doInBackground () เมื่อใช้เวลามากเกินไปในการดำเนินการที่ไม่ได้อยู่ที่ onPreExecute () ฉันต้องการยกเลิกเฉพาะ AsyncTask อินสแตนซ์นี้ซึ่งใช้เวลามากเกินไปและทำให้คนอื่น ๆ ขอบคุณมาก ความคิดเห็นของคุณ
Ayman Mahgoub

2
ฉันคิดว่าข้อความของฉันไม่ชัดเจนพอ ฉันไม่ได้บอกว่าคุณควรยกเลิกใน onPreExecute () ฉันบอกว่าคุณควรสร้าง Handler ใน onPreExecute () และโพสต์การยกเลิกล่าช้าจากเธรดหลัก ด้วยวิธีนี้คุณจะใช้เธรดหลักเป็นเธรด looper และแน่นอนคุณสามารถยกเลิก AsyncTask ได้ในภายหลังในขณะที่ doInBackground () กำลังดำเนินการเนื่องจากเธรดหลักทำงานพร้อมกันกับเธรดพื้นหลัง
BladeCoder

-1

ฉันสามารถหาวิธีแก้ปัญหาที่คล้ายกันนี้ได้ด้วยการเพิ่มบรรทัดง่ายๆ

HttpURLConnection hConn = (HttpURLConnection) url.openConnection();
hConn.setRequestMethod("HEAD");

ความต้องการของฉันคือการรู้รหัสตอบกลับและการได้รับข้อมูลเมตาก็เพียงพอแล้วแทนที่จะได้รับเนื้อหาตอบกลับที่สมบูรณ์

วิธีการร้องขอเริ่มต้นคือ GET และต้องใช้เวลามากในการส่งคืนในที่สุดก็โยน SocketTimeoutException ให้ฉัน การตอบสนองค่อนข้างรวดเร็วเมื่อฉันตั้งค่าวิธีการขอเป็น HEAD


1
นี่ไม่ใช่วิธีแก้ปัญหา แต่อย่างใดคุณกำลังเปลี่ยนวิธีการHEADร้องขอเป็นคำขอซึ่งจะไม่สร้างเนื้อหาตอบสนองใด ๆ
Sveinung Kval Bakken

สิ่งนี้ไม่ได้เพิ่มอะไรให้กับคำถามเดิม OP มี.setRequestMethod("HEAD")อยู่ในรหัส น่าแปลกที่คำอธิบายนี้เป็นสิ่งที่ฉันต้องการเพื่อลดปัญหา "เปิดไฟล์มากเกินไป" ขอบคุณมาก?
Joshua Pinter
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.