You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

调用Google Geolocation API时持续触发FileNotFoundException求助

问题

调用Google Geolocation API时触发FileNotFoundException,确认已使用POST请求方式,先后尝试两种实现代码仍未解决:

初始实现代码

Activity代码

String url = "https://www.googleapis.com/geolocation/v1/geolocate?key=API_KEY";
LocationAsyncTask task = new LocationAsyncTask(this);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
    task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, url);
else
    task.execute(url);

AsyncTask代码

protected Void doInBackground(String... param) {
    HttpsConnectionHelper conn = new HttpsConnectionHelper(weakContext.get());
    String response = conn.httpPost(param[0]);
    Log.d(MainActivity.LOG_TAG, "LocationAsyncTask = " + response);
    return null;
}

HttpsConnectionHelper代码

String httpPost(String requestURL) {
        Log.d(MainActivity.LOG_TAG, "HttpsConnectionHelper# requestURL = " + requestURL);
    URL url;
    HttpsURLConnection conn = null;

    try {
        //Create connection
        url = new URL(requestURL);
        conn = (HttpsURLConnection) url.openConnection();
        Log.d(MainActivity.LOG_TAG, "HttpsConnectionHelper# url.openConnection()");

        conn.setDoInput(true);
        conn.setDoOutput(true);
        conn.setRequestMethod("POST");
        conn.setRequestProperty("Content-Type", "application/json");
        conn.setRequestProperty("Accept", "application/json");
        conn.connect();

        Log.d(MainActivity.LOG_TAG, "HttpsConnectionHelper# conn.connect()");

        //Get Response
        InputStream is = conn.getInputStream();
        Log.d(MainActivity.LOG_TAG, "HttpsConnectionHelper# is.available() = "+is.available());
        BufferedReader rd = new BufferedReader(new InputStreamReader(is));
        String line;
        StringBuilder response = new StringBuilder();

        while ((line = rd.readLine()) != null) {
            response.append(line);
        }

        rd.close();
        return response.toString();

    } catch (Exception e) {
        e.printStackTrace();
        Log.d(MainActivity.LOG_TAG, "HttpsConnectionHelper#Exception# e.getMessage() = "+e.getMessage());

    } finally {
        if (conn != null) {
            conn.disconnect();
        }
    }

    return "";
}

编辑补充:参考官方curl重写代码

官方curl示例:

curl -X POST "https://www.googleapis.com/geolocation/v1/geolocate?key=YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d \
'{ "homeMobileCountryCode":310,
   "homeMobileNetworkCode":410,
   "radioType":"gsm",
   "carrier":"Vodafone",
   "considerIp":true
}'

重写后的Android代码:

public class GeolocationTask extends AsyncTask<Void, Void, String> {

@Override
protected String doInBackground(Void... params) {
    String apiUrl = "https://www.googleapis.com/geolocation/v1/geolocate?key=API_KEY";
    Log.d(MainActivity.LOG_TAG, "GeolocationTask# doInBackground() apiUrl = " + apiUrl);
    String requestBody = "{ " +
            "\"homeMobileCountryCode\":310, " +
            "\"homeMobileNetworkCode\":410, " +
            "\"radioType\":\"gsm\", " +
            "\"carrier\":\"Vodafone\", " +
            "\"considerIp\":true " +
            "}";

    try {
        URL url = new URL(apiUrl);
        HttpURLConnection connection = (HttpURLConnection) url.openConnection();

        // Set up the connection
        connection.setRequestMethod("POST");
        connection.setRequestProperty("Content-Type", "application/json");
        connection.setDoOutput(true);

        Log.d(MainActivity.LOG_TAG, "GeolocationTask# doInBackground() before write");
        // Write the request body
        try (OutputStream os = connection.getOutputStream()) {
            byte[] input = requestBody.getBytes("utf-8");
            os.write(input, 0, input.length);
        }

        Log.d(MainActivity.LOG_TAG, "GeolocationTask# doInBackground() after write");

        // Read the response
        try (BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream(), "utf-8"))) {
            StringBuilder response = new StringBuilder();
            String responseLine = null;
            while ((responseLine = br.readLine()) != null) {
                response.append(responseLine.trim());
            }
            Log.d(MainActivity.LOG_TAG, "GeolocationTask# doInBackground() response.toString() = "+response.toString());
            return response.toString();
        }
    } catch (IOException e) {
        e.printStackTrace();
        Log.d(MainActivity.LOG_TAG, "GeolocationTask# doInBackground()# Excep = "+e.getMessage());
    }

    return null;
}

@Override
protected void onPostExecute(String result) {
    super.onPostExecute(result);

    // Handle the result, e.g., parse the JSON response
    if (result != null) {
        // Parse and handle the JSON response here
        Log.d(MainActivity.LOG_TAG, "LocationAsyncTask(new) = " + result);
    }
}
}

两次实现均触发FileNotFoundException,需解决该问题。


解决思路与方案

FileNotFoundException在这里并非真的找不到文件,而是HTTP请求返回4xx/5xx错误码,Android的HttpURLConnection会将这类错误响应判定为"文件不存在"抛出异常。以下是具体排查和修复步骤:

1. 捕获错误响应流,获取真实错误信息

在代码的异常块中添加错误流读取逻辑,直接拿到Google API返回的具体错误原因:

catch (IOException e) {
    e.printStackTrace();
    // 读取API错误响应
    if (connection != null) {
        try {
            InputStream errorStream = connection.getErrorStream();
            if (errorStream != null) {
                BufferedReader br = new BufferedReader(new InputStreamReader(errorStream, "utf-8"));
                StringBuilder errorResponse = new StringBuilder();
                String line;
                while ((line = br.readLine()) != null) {
                    errorResponse.append(line.trim());
                }
                Log.d(MainActivity.LOG_TAG, "API错误响应: " + errorResponse.toString());
            }
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }
    Log.d(MainActivity.LOG_TAG, "GeolocationTask# doInBackground()# Excep = "+e.getMessage());
}

日志中的错误响应会直接指出问题,常见原因包括:API_KEY无效、API未启用、请求参数错误、配额耗尽等。

2. 检查API配置核心问题

  • 确认API_KEY有效且启用Geolocation API:登录Google Cloud控制台,验证API_KEY正确性,同时在"API和服务"中确认已启用"Geolocation API"。
  • 检查API_KEY限制:确保API_KEY没有设置过严的应用/IP限制(比如仅允许特定Android包名,而当前应用包名未添加)。
  • 验证请求参数合法性:如果使用模拟参数(如示例中的310/410 MCC/MNC),需确保参数符合目标区域运营商规范,或直接用considerIp: true仅基于IP定位做测试。

3. 代码层面优化

  • 添加Content-Length请求头(可选,避免服务器解析异常):在写入请求体前添加:
    connection.setRequestProperty("Content-Length", String.valueOf(requestBody.getBytes("utf-8").length));
    
  • 切换为HttpsURLConnection:Google API仅支持HTTPS,将原代码中的HttpURLConnection改为HttpsURLConnection:
    HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
    
  • 确保流关闭顺序:现有代码的try-with-resources已正确处理流关闭,无需额外修改,但要避免在流关闭前调用disconnect()。

4. 先通过外部工具验证API可用性

用Postman或curl直接调用API,确认API_KEY和参数能正常返回结果后,再迁移到Android代码,避免代码与API配置问题混淆。


内容的提问来源于stack exchange,提问作者Amit Yadav

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 12:05:55