我被赋予了将我们的应用程序从 WebLogic 12.1.3 迁移到 Payara 4.1 的任务,并且遇到了一个问题,我觉得我或多或少地处于故障排除线的末尾。我们有一个 EJB(无状态 bean),它有两种方法,一种调用 Google Maps Directions API,另一种调用 Google Maps Geocoding API,两者都使用相同的凭据和 Google 的 Java 客户端库。这两种方法都可以在 WebLogic 上完美运行,但是在切换到 Payara 后,使用 Directions API 的方法给了我一个错误。这是堆栈跟踪的相关部分:
java.io.IOException: Server Error: 403 Forbidden
at com.google.maps.internal.OkHttpPendingResult.parseResponse(OkHttpPendingResult.java:258)
at com.google.maps.internal.OkHttpPendingResult.await(OkHttpPendingResult.java:167)
at com.google.maps.PendingResultBase.await(PendingResultBase.java:56)
at com.somecompany.integration.GoogleDirectionsIntegration.getDirections(GoogleDirectionsIntegration.java:XXX)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
因此,地理编码方法仍然适用于两个平台,但是在尝试调用 Directions API 时,我从 Google 收到了 403,表明我的凭据被弄乱了,但同样的凭据适用于地理编码调用。代码没有以任何方式从一个平台切换到另一个平台。
更令人困惑的是,如果我从日志中获取调用 Google 的实际 URL 并在我的浏览器中尝试,即粘贴“ https://maps.googleapis.com/maps/api/directions/json?client= gme-company&mode=driving&arrival_time=1435825037&o rigin =Somewhere&destination=Somewhere+else&alternat ives=false&signature=nfre3XYZ2kmuDX8Qibce87ZFKQQ=" 进入 Chrome,它可以工作。我从谷歌得到了正确的答案。(顺便说一句,这些不是我使用的实际凭据或来源和目的地,它们已被“匿名化”:-))。我还检查了此 URL(由客户端库构建)在两个平台上运行时是否相同,并且在 Google 的开发人员页面上使用了 URL 签名调试器,但无济于事。我的凭据应该没有问题。
我真的走到了尽头,花了几天的时间进行故障排除和在线搜索,但没有找到解决方案。
没那么重要,但我自己没有编写这段代码,当然写的人不再在这里工作了:-P
无论如何,这是代码(有点匿名):
@Stateless
public class GoogleDirectionsIntegration {
private static final Logger LOGGER = Logger.getLogger(GoogleDirectionsIntegration.class.getName());
private GeoApiContext context = null;
/**
* Initializer
*/
@PostConstruct
public void init() {
LOGGER.log(Level.INFO, "initiating {0}", this.getClass().getSimpleName());
this.context = new GeoApiContext().setEnterpriseCredentials("gme-company", "companyGoogleCryptographicSecret");
this.context.setReadTimeout(1, TimeUnit.SECONDS)
.setRetryTimeout(1, TimeUnit.SECONDS)
.setConnectTimeout(1, TimeUnit.SECONDS)
.setWriteTimeout(1, TimeUnit.SECONDS);
OkHttpRequestHandler okHttpRequestHandler = null;
OkHttpClient okHttpClient = null;
try {
Field requestField = this.context.getClass().getDeclaredField("requestHandler");
requestField.setAccessible(true);
okHttpRequestHandler = (OkHttpRequestHandler) requestField.get(this.context);
Field f = okHttpRequestHandler.getClass().getDeclaredField("client");
f.setAccessible(true);
okHttpClient = (OkHttpClient) f.get(okHttpRequestHandler);
} catch (NoSuchFieldException | SecurityException | IllegalAccessException | IllegalArgumentException e) {
throw new IllegalStateException("Failed to create SSL context", e);
}
SSLContext sslCtx = this.getSslContext();
if (sslCtx != null && okHttpClient != null) {
SSLSocketFactory sslSocketFactory = sslCtx.getSocketFactory();
okHttpClient.setSslSocketFactory(sslSocketFactory);
}
}
private SSLContext getSslContext() {
TrustManager[] tm = new TrustManager[] {
new CustomTrustManager()
};
SSLContext sslContext = null;
try {
sslContext = SSLContext.getInstance("TLSv1.2");
sslContext.init(null, tm, new SecureRandom());
} catch (NoSuchAlgorithmException | KeyManagementException ex) {
throw new IllegalStateException("Failed to create SSL context", ex);
}
return sslContext;
}
public DirectionsRoute getDirections(final String origin, final String destination, final DistanceUnit distanceUnit,
@Nullable TransportMode mode, @NotNull Instant arrivalTime) throws NotFoundException {
TransportMode actualMode = mode == null ? TransportMode.CAR : mode;
DirectionsRoute[] directionsRoutes;
DirectionsApiRequest directionsApiRequest = DirectionsApi.getDirections(this.context, origin, destination);
directionsApiRequest.arrivalTime(new Instant(arrivalTime));
directionsApiRequest.alternatives(false);
directionsApiRequest.mode(this.toTravelMode(actualMode));
try {
DirectionsResult res = directionsApiRequest.await(); // THIS IS WHERE IT BREAKS!
directionsRoutes = res.routes;
} catch (Exception e) {
LOGGER.log(Level.WARNING, e.getMessage(), e);
throw new NotFoundException(e.getMessage());
}
if (directionsRoutes.length != 1) {
throw new NotFoundException("Failed to fetch valid directions");
}
return directionsRoutes[0];
}
public void getAddress(LatLng startLocation, Location location, boolean cacheOverride) throws Exception {
com.google.maps.model.LatLng gLatLng = new com.google.maps.model.LatLng(startLocation.getLat(), startLocation.getLng());
GeocodingApiRequest geocodingApiRequest = GeocodingApi.reverseGeocode(this.context, gLatLng);
GeocodingResult[] geocodingResults;
geocodingResults = geocodingApiRequest.await();
if (0 < geocodingResults.length) {
//.. Code that does stuff with the result..
} else {
LOGGER.log(Level.WARNING, "Received empty results from Google reverse geocode for [{0}].", startLocation);
}
}
}