java - Google Cloud Endpoints - API 方法仅在删除用户参数时成功调用
问题描述
我在一个应用程序中有一个 API 方法(用 Java 编写),它部署为一组在 Google Cloud 上运行的端点。API 使用 OpenAPI 并使用 ESP(可扩展服务代理)中继来自 API 的请求并调解任何身份验证。
我创建了一个新的 API 方法,如下所示:
@ApiMethod(path="my/path/{param}",httpMethod = "get")
public Object[] GetSomethingUsingFirebaseAuthentication(@Named("param") String param) throws UnauthorizedException,BadRequestException,NotFoundException
{
// implementation
}
我可以在本地运行时使用 Debug As > App Engine 进行调试,当我使用“debug as > app engine”进行调试时,我可以使用 Postman 调用如下方法。我正在使用的 Postman 设置如下(请注意,我在 Authorization 标头的“承载”中传递了一个身份验证令牌):
方法调用成功并返回成功响应,证明我调用方法正确且有效。如果我随后添加一个参数来接受这样的 Firebase 用户,则该方法将失败:
@ApiMethod(path="my/path/{param}",httpMethod = "get")
public Object[] GetSomethingUsingFirebaseAuthentication(@Named("param") String param, User user) throws UnauthorizedException,BadRequestException,NotFoundException
{
// some auth code based on the Firebase 'user'
}
现在我添加了 User 参数后调用该方法,与使用 Postman 之前的方式完全相同,现在我得到一个 http 503 错误:
method_info is not set
这是实际的 http JSON 响应:
{
"error": {
"errors": [
{
"domain": "global",
"reason": "backendError",
"message": "backend error"
}
],
"code": 503,
"message": "backend error"
}
}
这个问题与这个问题非常相似:
Google Cloud Endpoints + Firebase 身份验证:未设置 method_info
不过,与我的问题不同的是,当我将端点 API 部署到生产环境时,我仍然会遇到问题。
我还有其他非常相似的 API 方法可以接受 Firebase 用户,它们都在生产中工作。当我在本地调试它时,其中一种类似的 API 方法也有效,因此我不需要更改配置。
上述问题的公认答案(修改 web.xml 中的映射以使应该注入 method_info 的过滤器工作)对我不起作用。无论如何,这对我自己的问题来说是一个 hack,因为其他 API 方法似乎在本地和生产中工作。
关于这应该如何工作的一些解释 - ESP(可扩展服务代理),它是谷歌云的东西,是端点 API 的包装器,它可以使用用户的 Firebase 令牌调解身份验证(在我的情况下,这个令牌被传递在 Authorization 标头的 Bearer 中)。然后应将经过身份验证的 Firebase 用户作为user
参数传入。
这是完整的堆栈跟踪
WARNING: exception occurred while invoking backend method
java.lang.IllegalStateException: method_info is not set in the request
at com.google.api.server.spi.auth.EspAuthenticator.authenticate(EspAuthenticator.java:67)
at com.google.api.server.spi.request.Auth.authenticate(Auth.java:101)
at com.google.api.server.spi.request.ServletRequestParamReader.getUser(ServletRequestParamReader.java:205)
at com.google.api.server.spi.request.ServletRequestParamReader.deserializeParams(ServletRequestParamReader.java:141)
at com.google.api.server.spi.request.RestServletRequestParamReader.read(RestServletRequestParamReader.java:135)
at com.google.api.server.spi.SystemService.invokeServiceMethod(SystemService.java:349)
at com.google.api.server.spi.handlers.EndpointsMethodHandler$RestHandler.handle(EndpointsMethodHandler.java:119)
at com.google.api.server.spi.handlers.EndpointsMethodHandler$RestHandler.handle(EndpointsMethodHandler.java:102)
at com.google.api.server.spi.dispatcher.PathDispatcher.dispatch(PathDispatcher.java:50)
at com.google.api.server.spi.EndpointsServlet.service(EndpointsServlet.java:72)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:790)
at com.google.inject.servlet.ServletDefinition.doServiceImpl(ServletDefinition.java:287)
at com.google.inject.servlet.ServletDefinition.doService(ServletDefinition.java:277)
at com.google.inject.servlet.ServletDefinition.service(ServletDefinition.java:182)
at com.google.inject.servlet.ManagedServletPipeline.service(ManagedServletPipeline.java:91)
at com.google.inject.servlet.FilterChainInvocation.doFilter(FilterChainInvocation.java:85)
at com.google.api.control.ControlFilter.doFilter(ControlFilter.java:229)
at com.google.inject.servlet.FilterChainInvocation.doFilter(FilterChainInvocation.java:82)
at com.google.api.control.ConfigFilter.doFilter(ConfigFilter.java:120)
at com.google.inject.servlet.FilterChainInvocation.doFilter(FilterChainInvocation.java:82)
at com.google.inject.servlet.ManagedFilterPipeline.dispatch(ManagedFilterPipeline.java:119)
at com.google.inject.servlet.GuiceFilter$1.call(GuiceFilter.java:133)
at com.google.inject.servlet.GuiceFilter$1.call(GuiceFilter.java:130)
at com.google.inject.servlet.GuiceFilter$Context.call(GuiceFilter.java:203)
at com.google.inject.servlet.GuiceFilter.doFilter(GuiceFilter.java:130)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1642)
at com.google.appengine.tools.development.ResponseRewriterFilter.doFilter(ResponseRewriterFilter.java:134)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1642)
at com.google.appengine.tools.development.HeaderVerificationFilter.doFilter(HeaderVerificationFilter.java:34)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1642)
at com.google.appengine.api.blobstore.dev.ServeBlobFilter.doFilter(ServeBlobFilter.java:63)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1642)
at com.google.apphosting.utils.servlet.TransactionCleanupFilter.doFilter(TransactionCleanupFilter.java:48)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1642)
at com.google.appengine.tools.development.jetty9.StaticFileFilter.doFilter(StaticFileFilter.java:123)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1642)
at com.google.appengine.tools.development.DevAppServerModulesFilter.doDirectRequest(DevAppServerModulesFilter.java:366)
at com.google.appengine.tools.development.DevAppServerModulesFilter.doDirectModuleRequest(DevAppServerModulesFilter.java:349)
at com.google.appengine.tools.development.DevAppServerModulesFilter.doFilter(DevAppServerModulesFilter.java:116)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1642)
at com.google.appengine.tools.development.DevAppServerRequestLogFilter.doFilter(DevAppServerRequestLogFilter.java:44)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1634)
at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:533)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:146)
at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:524)
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:132)
at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:257)
at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:1595)
at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:255)
at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1340)
at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:203)
at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:473)
at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:1564)
at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:201)
at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1242)
at com.google.appengine.tools.development.jetty9.DevAppEngineWebAppContext.doScope(DevAppEngineWebAppContext.java:94)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:144)
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:132)
at com.google.appengine.tools.development.jetty9.JettyContainerService$ApiProxyHandler.handle(JettyContainerService.java:595)
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:132)
at org.eclipse.jetty.server.Server.handle(Server.java:503)
at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:364)
at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:260)
at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:305)
at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:103)
at org.eclipse.jetty.io.ChannelEndPoint$2.run(ChannelEndPoint.java:118)
at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:765)
at org.eclipse.jetty.util.thread.QueuedThreadPool$2.run(QueuedThreadPool.java:683)
at java.lang.Thread.run(Unknown Source)
调试时我在 Eclipse 中得到的唯一警告是
WARNING: No file found for: /_ah/start
关于可能导致此问题的任何想法,或者我可以查看什么?任何关于我如何调试或诊断问题的建议都非常感谢:)
解决方案
需要重新生成端点 API 的 OpenAPI 文件并将其部署到生产Google Cloud 端点,以便身份验证在本地调试时工作。
$ mvn clean package endpoints-framework:openApiDocs -DskipTests
$ gcloud endpoints services deploy target/openapi-docs/openapi.json
$ mvn appengine:run
端点 API 的本地版本引用了仅限生产的 Firebase 身份验证服务,该服务又必须从openapi.json
生产端点 API 中获取其端点 API 引用。
来自 Google OpenAPI 概述:
OpenAPI 文档描述了 REST API 的表面,并定义了以下信息:
API 的名称和描述。API 中的各个端点(路径)。如何对调用者进行身份验证。
推荐阅读
- git - 为什么 git diff 包含已合并的提交?
- javascript - UnhandledPromiseRejection:错误:Joi 的消息选项无效
- animation - 基于 D3 力的布局可以旋转节点吗?
- javascript - 对 D3 树中的工具提示应用缩放
- java - 无法调用方法,因为注入为空
- javascript - 如何让Deck相互堆叠反应原生
- java - Hadoop 卡在 INFO mapreduce.Job 上:正在运行的作业:job_1615924350035_0005`
- swift - 如何在网络操作工作流中添加 throw
- python - 最多只使用一列重新采样数据帧,同时保留该最大值的其他特征
- javascript - 如何防止 .map 从嵌套表中创建重复结果?