【发布时间】:2016-08-23 23:11:18
【问题描述】:
我想简单地从应用引擎中提取我的存储桶内容列表并显示它们。
但是,当我部署相同的代码应用引擎时,我收到 403 FORBIDDEN 错误。
com.google.api.client.googleapis.json.GoogleJsonResponseException: 403 FORBIDDEN
{
"code" : 403,
"errors" : [ {
"domain" : "global",
"message" : "Forbidden",
"reason" : "forbidden"
} ],
"message" : "Forbidden"
}
at com.google.api.client.googleapis.json.GoogleJsonResponseException.from(GoogleJsonResponseException.java:145)
at com.google.api.client.googleapis.services.json.AbstractGoogleJsonClientRequest.newExceptionOnError(AbstractGoogleJsonClientRequest.java:113)
at com.google.api.client.googleapis.services.json.AbstractGoogleJsonClientRequest.newExceptionOnError(AbstractGoogleJsonClientRequest.java:40)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest$1.interceptResponse(AbstractGoogleClientRequest.java:321)
at com.google.api.client.http.HttpRequest.execute(HttpRequest.java:1056)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:419)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:352)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.execute(AbstractGoogleClientRequest.java:469)
at com.alpine.servlets.TempServlet.getBucket(TempServlet.java:67)
at com.alpine.servlets.TempServlet.doGet(TempServlet.java:79)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:617)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:511)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1166)
at com.google.apphosting.utils.servlet.ParseBlobUploadFilter.doFilter(ParseBlobUploadFilter.java:125)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
at com.google.apphosting.runtime.jetty.SaveSessionFilter.doFilter(SaveSessionFilter.java:37)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
at com.google.apphosting.utils.servlet.JdbcMySqlConnectionCleanupFilter.doFilter(JdbcMySqlConnectionCleanupFilter.java:60)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
at com.google.apphosting.utils.servlet.TransactionCleanupFilter.doFilter(TransactionCleanupFilter.java:50)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:388)
at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)
at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:182)
at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:765)
at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:418)
at com.google.apphosting.runtime.jetty.AppVersionHandlerMap.handle(AppVersionHandlerMap.java:260)
at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
at org.mortbay.jetty.Server.handle(Server.java:326)
at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:542)
at org.mortbay.jetty.HttpConnection$RequestHandler.headerComplete(HttpConnection.java:923)
at com.google.apphosting.runtime.jetty.RpcRequestParser.parseAvailable(RpcRequestParser.java:78)
at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:404)
at com.google.apphosting.runtime.jetty.JettyServletEngineAdapter.serviceRequest(JettyServletEngineAdapter.java:148)
at com.google.apphosting.runtime.JavaRuntime$RequestRunnable.run(JavaRuntime.java:468)
at com.google.tracing.TraceContext$TraceContextRunnable.runInContext(TraceContext.java:439)
at com.google.tracing.TraceContext$TraceContextRunnable$1.run(TraceContext.java:446)
at com.google.tracing.CurrentContext.runInContext(CurrentContext.java:256)
at com.google.tracing.TraceContext$AbstractTraceContextCallback.runInInheritedContextNoUnref(TraceContext.java:310)
at com.google.tracing.TraceContext$AbstractTraceContextCallback.runInInheritedContext(TraceContext.java:302)
at com.google.tracing.TraceContext$TraceContextRunnable.run(TraceContext.java:443)
at com.google.apphosting.runtime.ThreadGroupPool$PoolEntry.run(ThreadGroupPool.java:235)
at java.lang.Thread.run(Thread.java:745)
通过我的research,我确定此错误有很多潜在原因。
- 拒绝访问
- 帐户问题
- AnotherUserOwnsDomain
- BucketAlreadyExists
- 禁止跨位置记录
- 需要域验证
- 配额不足
- 无效的AccessKeyId
- 无效付款人
- 安全性无效
- RequestTimeTooSkewed
- SignatureDoesNotMatch
但是,我无法从堆栈跟踪中确定哪些适用于我的情况。
关于这个主题的Google doc 表明我不应该做任何特别的事情来让它工作:
如果您在 Google App Engine 或 Google 上运行您的应用程序 Compute Engine,环境已经提供了一个服务帐号的 身份验证信息,因此无需进一步设置。为了 Compute Engine,服务帐号范围取决于您的创建方式 实例。请参阅设置服务帐户访问范围 实例。对于 App Engine,使用云平台范围。
应用引擎实例和云存储桶在不同的项目中,但我认为这应该不是问题,因为范围设置为云平台。
doc 将云平台范围描述为:
查看和管理所有 Google Cloud Platform 服务的数据。为了 谷歌云存储,这个和 devstorage.full-control 一样。
我用来建立连接的代码是直接从谷歌的java-doc-samples借来的:
public class StorageFactory {
private static Storage instance = null;
public static synchronized Storage getService() throws IOException, GeneralSecurityException {
if (instance == null) {
instance = buildService();
}
return instance;
}
private static Storage buildService() throws IOException, GeneralSecurityException {
HttpTransport transport = GoogleNetHttpTransport.newTrustedTransport();
JsonFactory jsonFactory = new JacksonFactory();
GoogleCredential credential = GoogleCredential.getApplicationDefault(transport, jsonFactory);
if (credential.createScopedRequired()) {
Collection<String> bigqueryScopes = StorageScopes.all();
credential = credential.createScoped(bigqueryScopes);
}
return new Storage.Builder(transport, jsonFactory, credential)
.setApplicationName("GCS Samples")
.build();
}
}
我对如何调试这个问题感到有些困惑。
【问题讨论】:
-
您对存储桶设置了哪些权限?它们是否包含您的应用引擎服务帐号?
-
权限目前不包括来自其他项目的应用引擎服务帐号。目前还不清楚如何将特定类型的权限添加到存储桶中。
-
默认情况下,包括服务帐户在内的项目成员可能具有读取权限。如果您专门设置了权限,则需要包含服务帐户。它和其他任何用户一样都算作用户,因此请添加授予其电子邮件地址读取权限。
-
效果很好。谢谢。
标签: google-app-engine google-cloud-storage google-api-java-client