google-cloud-endpoints - Google 的 Endpoints 中的 EndpointsServlet 类有什么作用?
问题描述
首先,我是 java servlet、maven 项目和 api 的初学者。
我正在做以下关于开始使用 google 端点的教程,这是一个在 github 上实现以下 maven 项目源代码的教程。在 web.xml 中,只有一个叫 Servlet,EndpointsServlet 是这样的:
<!-- wrap the backend with Endpoints Framework v2. -->
<servlet>
<servlet-name>EndpointsServlet</servlet-name>
<servlet-class>com.google.api.server.spi.EndpointsServlet</servlet-class>
<init-param>
<param-name>services</param-name>
<param-value>com.example.echo.Echo</param-value>
</init-param>
</servlet>
我不明白的是为什么项目中没有其他 servlet?主目录中只有3 个 java 类,它们都不是 servlet 文件。我假设这个项目是一个带有服务器端逻辑(例如路由和响应请求)的示例 api,就像任何其他 servlet 项目一样,这意味着应该有比这个 servlet 更多的东西。
web.xml 上的评论是关于它做什么的明显线索,但我真的不知道用端点框架包装后端是什么意思。此外,我实际上得到了 EndpointsServlet.java 文件,它说 servlet 是“用于无代理 API 服务的处理程序。这个 servlet 理解并以 JSON-REST 回复。再说一次,我真的不理解这个评论,也不理解 servlet 的作用阅读它。下面的 Servlet 代码:
package com.google.api.server.spi;
import com.google.api.server.spi.SystemService.EndpointNode;
import com.google.api.server.spi.config.ApiConfigException;
import com.google.api.server.spi.config.model.ApiClassConfig.MethodConfigMap;
import com.google.api.server.spi.config.model.ApiConfig;
import com.google.api.server.spi.config.model.ApiMethodConfig;
import com.google.api.server.spi.dispatcher.PathDispatcher;
import com.google.api.server.spi.handlers.ApiProxyHandler;
import com.google.api.server.spi.handlers.CorsHandler;
import com.google.api.server.spi.handlers.EndpointsMethodHandler;
import com.google.api.server.spi.handlers.ExplorerHandler;
import com.google.common.collect.ImmutableList;
import java.io.IOException;
import java.util.Enumeration;
import java.util.List;
import java.util.Map.Entry;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* A handler for proxy-less API serving. This servlet understands and replies in JSON-REST.
*/
public class EndpointsServlet extends HttpServlet {
private static final String EXPLORER_PATH = "explorer";
private ServletInitializationParameters initParameters;
private SystemService systemService;
private PathDispatcher<EndpointsContext> dispatcher;
private CorsHandler corsHandler;
@Override
public void init(ServletConfig config) throws ServletException {
super.init(config);
ClassLoader classLoader = getClass().getClassLoader();
this.initParameters = ServletInitializationParameters.fromServletConfig(config, classLoader);
this.systemService = createSystemService(classLoader, initParameters);
this.dispatcher = createDispatcher();
this.corsHandler = new CorsHandler();
}
@Override
public void service(HttpServletRequest request, HttpServletResponse response) throws IOException {
String method = getRequestMethod(request);
if ("OPTIONS".equals(method)) {
corsHandler.handle(request, response);
} else {
String path = Strings.stripSlash(
request.getRequestURI().substring(request.getServletPath().length()));
EndpointsContext context = new EndpointsContext(method, path, request, response,
initParameters.isPrettyPrintEnabled());
if (!dispatcher.dispatch(method, path, context)) {
response.setStatus(HttpServletResponse.SC_NOT_FOUND);
response.getWriter().append("Not Found");
}
}
}
private String getRequestMethod(HttpServletRequest request) {
Enumeration headerNames = request.getHeaderNames();
String methodOverride = null;
while (headerNames.hasMoreElements()) {
String headerName = (String) headerNames.nextElement();
if (headerName.toLowerCase().equals("x-http-method-override")) {
methodOverride = request.getHeader(headerName);
break;
}
}
return methodOverride != null ? methodOverride.toUpperCase() : request.getMethod();
}
private PathDispatcher<EndpointsContext> createDispatcher() {
PathDispatcher.Builder<EndpointsContext> builder = PathDispatcher.builder();
List<EndpointNode> endpoints = systemService.getEndpoints();
// We're building an ImmutableList here, because it will eventually be used for JSON-RPC.
ImmutableList.Builder<EndpointsMethodHandler> handlersBuilder = ImmutableList.builder();
for (EndpointNode endpoint : endpoints) {
ApiConfig apiConfig = endpoint.getConfig();
MethodConfigMap methods = apiConfig.getApiClassConfig().getMethods();
for (Entry<EndpointMethod, ApiMethodConfig> methodEntry : methods.entrySet()) {
if (!methodEntry.getValue().isIgnored()) {
handlersBuilder.add(
new EndpointsMethodHandler(initParameters, getServletContext(), methodEntry.getKey(),
apiConfig, methodEntry.getValue(), systemService));
}
}
}
ImmutableList<EndpointsMethodHandler> handlers = handlersBuilder.build();
for (EndpointsMethodHandler handler : handlers) {
builder.add(handler.getRestMethod(), Strings.stripTrailingSlash(handler.getRestPath()),
handler.getRestHandler());
}
ExplorerHandler explorerHandler = new ExplorerHandler();
builder.add("GET", EXPLORER_PATH, explorerHandler);
builder.add("GET", EXPLORER_PATH + "/", explorerHandler);
builder.add("GET", "static/proxy.html", new ApiProxyHandler());
return builder.build();
}
private SystemService createSystemService(ClassLoader classLoader,
ServletInitializationParameters initParameters) throws ServletException {
try {
SystemService.Builder builder = SystemService.builder()
.withDefaults(classLoader)
.setStandardConfigLoader(classLoader)
.setIllegalArgumentIsBackendError(initParameters.isIllegalArgumentBackendError())
.setDiscoveryServiceEnabled(true);
for (Class<?> serviceClass : initParameters.getServiceClasses()) {
builder.addService(serviceClass, createService(serviceClass));
}
return builder.build();
} catch (ApiConfigException | ClassNotFoundException e) {
throw new ServletException(e);
}
}
/**
* Creates a new instance of the specified service class.
*
* @param serviceClass the class of the service to create
*/
protected <T> T createService(Class<T> serviceClass) {
try {
return serviceClass.newInstance();
} catch (InstantiationException e) {
throw new RuntimeException(
String.format("Cannot instantiate service class: %s", serviceClass.getName()), e);
} catch (IllegalAccessException e) {
throw new RuntimeException(
String.format("Cannot access service class: %s", serviceClass.getName()), e);
}
}
}
解决方案
EndpointsServlet
处理具有特定路径前缀的所有 API 调用。它接受一个 RESTful API 调用并将其转换为 POJO(s)并将其分派到您编写的 Java 方法,然后将该方法的返回值序列化为 JSON。它根据您如何注释代码来执行此操作。
推荐阅读
- laravel - 在使用 spatie webhook 客户端和 ngrok 测试 webhook 时,我一直找不到 404
- c++ - 为什么编译器优化会破坏我的代码?
- git - 使 git pull --recurse-submodules 更新子模块到子模块分支上的最新提交
- excel - 如果未找到错误,则在列中的单元格中搜索单词
- javascript - javascript element.scrollBy 不滚动给定距离
- upload - gsutil rsync 尝试在将源迁移到新存储后重新上传所有内容
- python - 基于数组值的不同颜色和 alpha 值
- rust - 在涉及线和地图的情况下对所有权感到困惑
- html - 某些 ID 在 CSS 中没有被修改,我该如何解决这个问题?
- elasticsearch - 为什么此查询会导致“子句过多”?