【问题标题】:HttpURLConnection.getInputStream() hangs and never finishesHttpURLConnection.getInputStream() 挂起并且永远不会完成
【发布时间】:2018-09-27 17:27:43
【问题描述】:

我正在尝试使用以下代码从 JSON 端点获取令牌:

public class FetchToken extends AsyncTask<String, Void, Void> {
    String data = "";
    String token = "";

    public TokenDelegate delegate = null;

    @Override
    protected Void doInBackground(String... identity) {
        try {
            if (identity.length == 1) {
                URL url = new URL(identity[0]);

                HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
                InputStream inputStream = httpURLConnection.getInputStream();
                BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
                String line = "";

                while (line != null) {
                    line = bufferedReader.readLine();
                    data = data + line;
                }

                JSONObject JO = new JSONObject(data);
                token = JO.get("token").toString();
            }
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (JSONException e) {
            e.printStackTrace();
        }

        return null;
    }

    @Override
    protected void onPostExecute(Void aVoid) {
        Log.d("token", token);
        //delegate.processFinish(token);
        super.onPostExecute(aVoid);
    }
}

我尝试在每一行之后打印到调试日志,似乎InputStream inputStream = httpURLConnection.getInputStream(); 行永远不会完成,其余代码也不会执行。但是,这发生在 AsyncTask 内部,并且该 AsyncTask 的 onPostExecute 方法正在触发,就好像任务已经完成一样,但它看起来好像已经完成了。

似乎没有执行任何 catch 块,当我检查 Android Profiler 中的网络面板时,请求说它没有传回任何东西。但是,在浏览器中访问 JSON 端点会使一切恢复正常。

希望有人知道问题可能是什么。我试图用谷歌搜索无济于事。如果需要更多信息,请告诉我。谢谢。

【问题讨论】:

  • the onPostExecute method of that AsyncTask is firing - 那么httpURLConnection.getInputStream() 正在工作,如果(identity.length == 1) 因为这是一个阻塞调用,你确定你没有捕获异常并返回null - 检查logcat ?还要确保关闭 finally 块中的流
  • 你找到正确的解决方案了吗?
  • 就我而言,这是因为我的模拟器无法连接到互联网

标签: java android android-studio android-asynctask


【解决方案1】:

您很可能希望设置超时以确保在外部资源无法及时获得时连接失败。这些值以毫秒为单位,例如连接和读取的 5 秒超时将是:

 HttpURLConnection conn = ...
 conn.setConnectTimeout(5000);
 conn.setReadTimeout(5000);

默认情况下,超时设置为0,根据setConnectTimeout(),这意味着:

零超时被解释为无限超时。

【讨论】:

  • 感谢您的建议。不幸的是,这并没有解决问题。当我在浏览器中访问资源时,它确实比超时恢复得更快。
【解决方案2】:

InputStream inputStream = httpURLConnection.getInputStream(); 行从未完成,因为它正在抛出 java.security.cert.CertPathValidatorException。错误没有被记录,因为我没有在我的 try / catch 块中捕捉到这种类型的错误。

【讨论】:

    【解决方案3】:

    查看下面的代码并相应地修改您的代码。

    1) 如果方法是 GET,则数据或标头可以为空。

    示例用法

     url = <some url>
     Map<String, String> headers = new HashMap<String, String>();       
     headers.put("Content-Type", "application/json");       
     headers.put("Accept", "application/json");
    

    a) 获取:

    invokeHTTPRequest(url, "GET", headers, null);
    

    b) 发布

    Student st = new Student();
    Gson gson = new Gson();
    String jsonReqData = gson.toJson(st);
    String resp = invokeHTTPRequest3(url, "POST", headers,  jsonReqData);
    

    public static String invokeHTTPRequest(String urlString, String method, Map headers,String data) {

        URL url = null;
        try {
            url = new URL(urlString);
            HttpURLConnection conn = null;
            conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod(method);
            conn.setConnectTimeout(10000);
            conn.setReadTimeout(10000);
    
            if (headers != null) {
                for (Map.Entry<String, String> header : headers.entrySet()) {
                    conn.setRequestProperty(header.getKey(), header.getValue());
                }
            }
    
    
    
            if (data != null) {
                byte[] postDataBytes = data.toString().getBytes();
                conn.setRequestProperty("Content-Length", String.valueOf(postDataBytes.length));
                conn.setDoOutput(true);
                conn.getOutputStream().write(postDataBytes);
    
            }
    
            BufferedReader rd = null;
    
            if(conn.getResponseCode() == 200){
                rd = new BufferedReader(new InputStreamReader(conn.getInputStream()));
            }
            else{
                rd = new BufferedReader(new InputStreamReader(conn.getErrorStream()));
            }
    
            StringBuilder result = new StringBuilder();
    
            String line;
            while ((line = rd.readLine()) != null) {
                result.append(line);
            }
            rd.close();
    
    
            return result.toString();
    
        } catch (Exception e) {
            //handle exception here
        }
    
    }
    

    【讨论】:

      【解决方案4】:

      您忘记在HttpUrlConnection 上拨打connect

      HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
      httpURLConnection.connect();
      InputStream inputStream = httpURLConnection.getInputStream();
      

      【讨论】:

      • 用 .connect() 添加行似乎不能解决问题。
      • 其实connect() 是不需要的。只需调用url.openConnection(); 就足够了
      • 是的,我忘了 getInputStream() 会强制 connect() :/
      猜你喜欢
      • 2018-06-26
      • 2022-01-24
      • 1970-01-01
      • 2012-10-31
      • 2015-12-20
      • 2021-11-17
      • 2022-08-23
      • 1970-01-01
      • 2017-01-27
      相关资源
      最近更新 更多