当前位置: 首页 > 知识库问答 >
问题:

如何访问Swagger Codecen生成的JAXRS类上的请求标头

慕光赫
2023-03-14

我有一个带有Swagger API的项目,其服务器代码是由swagger-codegen-2.4.24为语言jaxrs生成的。

生成的代码有一个后缀为“*ApiService”的抽象类,它定义了一系列方法,每个方法对应于API的Swagger规范中定义的每个操作。

每个方法都有一个javax.ws.rs.core.SecurityContext接口局部变量。

现在,在扩展了"*ApiService"的自定义类上,显然javax.ws.rs.core.SecurityContext类局部变量,我需要获取请求标头"X-Forwarded-For"的值。

如果调试自定义类,我会看到SecurityContext接口是org.glassfish.jersey.server.internal.process的一个实例。SecurityContextInjectee,它有我需要的头。

既然我不能与SecurityContextInjectee一起工作,因为它是私有的,那么我如何获取这些信息?

我意识到,如果由swagger-codecen生成的类添加javax.servlet.http.HttpServlet请求类,除了SecurityContext之外,还可以访问请求参数,但我没有看到任何允许这样做的jaxrs参数。

期待您的评论。

共有1个答案

吴欣然
2023-03-14

在每个规范版本中,您可以定义一个<code>头</code>,就像可能的参数位置之一。

因此,一个可能的解决方案是在请求<code>参数</code>部分中所需的方法中定义头:

parameters:
    -
        name: X-Forwarded-For
        description: X-Formarwed-For header.
        schema:
            type: string
        in: header

或者,在 JSON 表示法中:

    "parameters": [
        {
            "name": "X-Forwarded-For",
            "description": "X-Formarwed-For header.",
            "schema": {
                "type": "string"
            },
            "in": "header"
        }
    ]

我知道这可能是一个不太容易维护的解决方案,因为您需要在每个请求中包含消息头,但是也许您可以在您的服务实现中使用继承来减轻这个问题。

有一个开放的Github问题要求您描述的行为,以一般方式处理头处理。

在这个相关的SO回答中也建议了一个合适的选项,就是修改API代码生成中使用的Mustache模板,并在其中包含所需的头处理。请注意,这将降低代码的可维护性,并且您将有执行一些改变的风险,这会破坏与官方Swagger Codegen库的兼容性。我不确定在Swagger Codegen中,但是在OpenAPI生成器中,有一个选项可以覆盖使用的模板,而不需要修改正式发行版中提供的实际模板。请看这个相关的SO问题。

尽管情况似乎不再如此,至少在旧版本的泽西中,类是公共,您也可以尝试通过反射访问org.glassfish.jersey.server.internal.process.SecurityContextIn的内部变量,尽管我认为这种解决方法使您的应用程序非常依赖于实现。在任何情况下,也许您可以定义这样一个实用程序方法,您可以在服务实现中重用它:

public static String getXForwardedForHeaderValue(final SecurityContext securityContext) {
  SecurityContextInjectee securityContextImpl = (SecurityContextInjectee) securityContext;
  Field requestContextField = SecurityContextInjectee.class.getDeclaredField("requestContext");
  requestContextField.setAccessible(true);
  ContainerRequestContext requestContext = requestContextField.get(securityContextImpl);
  String xForwardedForHeaderValue = requestContext.getHeaderString("X-Forwarded-For");
  return xForwardedForHeaderValue;
}

最后,另一种可能性是使用处理标头的过滤器。如果需要,您可以使用线程局部变量等方式将标头值传递给基础服务。这个想法将如下所示。

首先,定义一个方便的对象来包装您的< code>ThreadLocal值:

public class XForwardedForHeaderHolder{

    private static final ThreadLocal<String> value = new ThreadLocal<String>();

    public static void setXForwardedForHeader(String xForwardedFor) {
        value.set(xForwardedFor);
    }

    public static String getXForwardedForHeader() {
        return value.get();
    }

    public static void clean() {
        value.remove();
    }
}

接下来,创建一个 ContainerRequestFilter。此过滤器将从正在处理的 HTTP 请求中收到的信息中读取标头:

import java.io.IOException;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.SecurityContext;
import javax.ws.rs.ext.Provider;
 
@Provider
public class XForwardedForHeaderRequestFilter implements ContainerRequestFilter {
 
    @Override
    public void filter(ContainerRequestContext requestContext)
        throws IOException {
 
        String xForwardedForHeaderValue = requestContext.getHeaderString("X-Forwarded-For");
        XForwardedForHeaderHolder.setXForwardedForHeader(
            xForwardedForHeaderValue
        );
    }
}

最后,使用服务实现中的价值:

String xForwardedForHeaderValue = XForwardedForHeaderHolder.getXForwardedForHeader();
// Clean up
XForwardedForHeaderHolder.clean();

一方面,过滤器注册应该可以正常工作,但是它可能依赖于您使用的JAXRS版本和Swagger本身;另一方面,该解决方案假设过滤器将在线程局部变量中为底层服务的每个请求提供正确的头,换句话说,不存在任何与线程相关的问题。我认为应该是这样,但这是需要测试的东西。

 类似资料:
  • 如何在JAX-RS中实现WriterInterceptor接口时访问请求头? 完整的代码如下:

  • 问题内容: 我想捕获客户端JavaScript中的HTTP请求标头字段,主要是Referer和User-Agent。我该如何访问它们? Google Analytics(分析)设法通过将您嵌入到页面中的JavaScript来获取数据,因此绝对有可能。 问题答案: 如果要访问引荐来源网址和用户代理,客户端Javascript可以使用这些引荐来源网址和用户代理,但不能直接访问标头。 要检索引荐来源网址

  • 问题内容: 我的JavaScript应用程序需要确定资源的长度, 然后 才能使用Ajax下载资源。通常这不是问题,您只需发出HEAD请求并提取即可。 但是,资源存储在与客户端不同的服务器上。(我控制的服务器)。因此,我正在使用CORS发出跨域Ajax请求,并已设置服务器以使用自定义标头响应HEAD请求和GET / POST请求的预检请求。 总的来说,这很有效,但是在使用CORS时,我似乎找不到一种

  • 我有一个应用程序,将选择图像到画廊,并显示它的测试使用ImageView。我的问题是它不能在Android M上工作。我可以选择图像,但不能在我的测试中显示。他们说我需要得到允许才能在Android M上访问图像,但不知道怎么做。请帮帮忙。

  • 嗨,我正在使用SoapUI Pro来测试一组Soap网络服务。 我有一个 testRunListener,它将我的 soap 请求的请求和响应记录到它在运行测试时创建的文件中。在这里,我有一个if语句,该语句在记录请求和响应之前检查测试步骤的名称.. 而不是使用单个请求的名称,我想使用更通用的东西,例如请求的类型,可以是 createShipping 或 cancelShipping。这是因为我有

  • 问题内容: 我想将自定义标头添加到jQuery的AJAX POST请求中。 我已经试过了: 当我发送此请求并观看FireBug时,看到以下标头: 选项xxxx / yyyy HTTP / 1.1 主机:127.0.0.1:6666 用户代理:Mozilla / 5.0(Windows NT 6.1; WOW64; rv:11.0)Gecko / 20100101 Firefox / 11.0 接受