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

JavaScript调用Google地理定位REST API,回调外无法获取数据求助

问题根源与解决方案

你的代码本身没有语法错误,问题出在异步操作的执行顺序上!

当你调用xmlhttp.open('POST',url,true)时,第三个参数true表示这是一个异步请求。浏览器发送请求后,不会等着API返回结果,而是直接继续执行后面的代码——也就是你标注的[2 operation],这时候lat和lng还没被赋值,自然是null。而onreadystatechange回调函数要等API请求成功返回数据后才会执行,也就是你标注的[1 operation],这时候才能拿到有效的经纬度值。

下面给你几个可行的解决方案:

方案1:把业务逻辑放在回调函数内部

最直接的方式,就是把需要使用lat和lng的代码都放到onreadystatechange的成功回调里,或者封装成函数在回调里调用:

var postdata = '{"cellTowers":[{"cellId": '+cid+',"locationAreaCode": '+lac+',"mobileCountryCode": '+mcc+',"mobileNetworkCode": '+mnc+'}]}'
xmlhttp = new XMLHttpRequest();
var url = "https://www.googleapis.com/geolocation/v1/geolocate?key=YOURKEY";
xmlhttp.open('POST',url,true);
xmlhttp.setRequestHeader("Content-Type", "application/json");
xmlhttp.send(postdata);
var lat; var lng;

xmlhttp.onreadystatechange = function() {
 if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
 if (xmlhttp.responseText) {
 var data = xmlhttp.responseText;
 var json = JSON.parse(data);
 lat = json.location.lat;
 lng = json.location.lng;
 // 把需要用经纬度的逻辑放在这里,或者调用一个处理函数
 handleLocation(lat, lng);
 }
 }
};

// 封装处理逻辑的函数
function handleLocation(latitude, longitude) {
 alert(latitude + " " + longitude); // 这里能正常拿到值
 // 其他需要用经纬度的操作都可以在这里写
}

方案2:用Promise封装异步请求

如果不想把所有逻辑都塞进回调里,可以把XMLHttpRequest包装成Promise,用更清晰的链式调用或者async/await来处理:

function getLocation(cid, lac, mcc, mnc) {
  return new Promise((resolve, reject) => {
    var postdata = `{"cellTowers":[{"cellId": ${cid},"locationAreaCode": ${lac},"mobileCountryCode": ${mcc},"mobileNetworkCode": ${mnc}}]}`;
    const xmlhttp = new XMLHttpRequest();
    const url = "https://www.googleapis.com/geolocation/v1/geolocate?key=YOURKEY";
    xmlhttp.open('POST', url, true);
    xmlhttp.setRequestHeader("Content-Type", "application/json");
    xmlhttp.onreadystatechange = function() {
      if (xmlhttp.readyState == 4) {
        if (xmlhttp.status == 200) {
          const json = JSON.parse(xmlhttp.responseText);
          resolve({lat: json.location.lat, lng: json.location.lng});
        } else {
          reject(new Error('请求失败:' + xmlhttp.status));
        }
      }
    };
    xmlhttp.send(postdata);
  });
}

// 调用方式:链式调用
getLocation(cid, lac, mcc, mnc)
  .then(location => {
    alert(location.lat + " " + location.lng);
    // 这里可以处理拿到位置后的逻辑
  })
  .catch(error => {
    console.error(error);
  });

// 或者用async/await(需要在async函数里使用)
async function fetchLocation() {
  try {
    const location = await getLocation(cid, lac, mcc, mnc);
    alert(location.lat + " " + location.lng);
  } catch (error) {
    console.error(error);
  }
}
fetchLocation();

方案3:使用jQuery的$.ajax方法

既然你提到了jQuery,它的$.ajax方法本身就封装了异步请求,支持Promise风格,代码会更简洁:

var postdata = {
  cellTowers: [{
    cellId: cid,
    locationAreaCode: lac,
    mobileCountryCode: mcc,
    mobileNetworkCode: mnc
  }]
};

$.ajax({
  url: "https://www.googleapis.com/geolocation/v1/geolocate?key=YOURKEY",
  type: "POST",
  contentType: "application/json",
  data: JSON.stringify(postdata),
  success: function(response) {
    const lat = response.location.lat;
    const lng = response.location.lng;
    alert(lat + " " + lng);
    // 处理位置逻辑
  },
  error: function(xhr, status, error) {
    console.error('请求失败:', error);
  }
});

// 或者用Promise风格的$.ajax
$.ajax({
  url: "https://www.googleapis.com/geolocation/v1/geolocate?key=YOURKEY",
  type: "POST",
  contentType: "application/json",
  data: JSON.stringify(postdata)
})
.then(response => {
  const lat = response.location.lat;
  const lng = response.location.lng;
  alert(lat + " " + lng);
})
.catch(error => {
  console.error(error);
});

总结一下:异步请求的核心就是不要在请求未完成时去拿返回值,必须等请求成功的回调触发后,再处理返回的数据。上面的几种方案都能解决你的问题,你可以根据自己的代码风格选择合适的方式。

内容的提问来源于stack exchange,提问作者13hola

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 08:33:41