如何在 java EE 应用程序中使用丰富的 header 将请求代理到另一个位置
How to proxy a request to another location with enriched header in a java EE application
我面临以下问题。我需要在 Websphere 上的 java EE 应用程序 运行ning(没有 Spring)中创建一种方法来将请求代理到另一个位置并使用不记名令牌丰富 header .
举个例子
GET request: http://servicehost.com/proxy/targetapi/userresource
需要转发给
GET request: http://othertargethost.com/targetapi/userresource with Authorization: Bearer randomtoken
我在另一个应用程序中解决了这个问题,但这是一个使用 Netflix Zuul 和 spring-cloud-starter-netflix-zuul 的 spring 启动应用程序。
但是现在我处于严格的 EE 环境中,根本不允许 spring。我没有找到任何关于如何在纯 EE 上下文中设置或配置 netflix zuul 的好的文档或示例。
我还有哪些其他选择可以解决这个问题?我在考虑以下问题
- 在 **/proxy/* 上设置一个 Servlet 并创建一个过滤器来进行转发
- 在 Internet 上搜索类似于 Zuul 的东西,并在 运行 EE
中找到更好的文档
- ...
我真的很感激任何给我指明正确方向的东西。
Jersey web service proxy 对我来说不是解决方案,因为这是在特定端点和特定 http 方法上精确定位的
GET request: http://servicehost.com/proxy/targetapi/userresource
可能是
GET request: http://servicehost.com/proxy/targetapi/contractresource
或
GET request: http://servicehost.com/proxy/specialapi/userresource
并且它需要能够处理 GET、POST、PUT 和 DELETE
我无法在 EE 中使用 Zuul,所以我只有一种方法,那就是编写自己的 servlet
@WebServlet(name = "ProxyServlet", urlPatterns = {"/proxy/*"})
public class ProxyServlet extends HttpServlet {
public static final String SESSION_ID_PARAM = "delijnSessionId";
@Inject
private Logger logger;
@Inject
private ProxyProperties proxyProperties;
@Inject
private SecurityService securityService;
@Inject
private ProxyHttpClientFactory proxyHttpClientFactory;
@Inject
private StreamUtils streamUtils;
@Override
protected void doGet(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws ServletException, IOException {
proxy(httpServletRequest, httpServletResponse);
}
@Override
protected void doPost(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws ServletException, IOException {
proxy(httpServletRequest, httpServletResponse);
}
@Override
protected void doPut(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws ServletException, IOException {
proxy(httpServletRequest, httpServletResponse);
}
@Override
protected void doDelete(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws ServletException, IOException {
proxy(httpServletRequest, httpServletResponse);
}
private void proxy(HttpServletRequest request, HttpServletResponse response) {
try {
String requestUrl = request.getRequestURI();
String method = request.getMethod();
String sessionId = getSessionId(request);
String protocol = proxyProperties.getProperty(ProxyProperties.PROXY_PROTOCOL);
String server = proxyProperties.getProperty(ProxyProperties.PROXY_SERVER);
String port = proxyProperties.getProperty(ProxyProperties.PROXY_PORT);
String newPath = requestUrl.replaceFirst(".*/proxy", "");
URI uri = new URI(protocol, null, server, Integer.parseInt(port), newPath, request.getQueryString(), null);
ProxyHttpMethod proxyRequest = new ProxyHttpMethod(method);
proxyRequest.setURI(uri);
copyBodyFromRequest(request, method, proxyRequest);
copyHeadersFromRequest(request, proxyRequest);
enrichWithAccessToken(proxyRequest, sessionId);
try (CloseableHttpClient client = proxyHttpClientFactory.produce()) {
logger.info("uri [{}]", uri);
logger.info("method [{}]", method);
execute(client, proxyRequest, response);
} catch (IOException e) {
throw new TechnicalException(e);
}
} catch (URISyntaxException | IOException e) {
throw new TechnicalException(e);
}
}
private void execute(CloseableHttpClient client, ProxyHttpMethod proxyHttpMethod, HttpServletResponse response) {
try (CloseableHttpResponse proxyResponse = client.execute(proxyHttpMethod)) {
int statusCode = proxyResponse.getStatusLine().getStatusCode();
if (statusCode >= 200 || statusCode < 300) {
response.setStatus(statusCode);
HttpEntity entity = proxyResponse.getEntity();
if(entity != null){
String result = streamUtils.getStringFromStream(entity.getContent());
logger.trace("result [" + result + "]");
response.getWriter().write(result);
response.getWriter().flush();
response.getWriter().close();
}
} else {
throw new TechnicalException("[" + statusCode + "] Error retrieving access token");
}
} catch (IOException e) {
throw new TechnicalException(e);
}
}
private void enrichWithAccessToken(ProxyHttpMethod proxyRequest, String sessionId) {
Optional<TokenDto> token = securityService.findTokenBySessionIdWithRefresh(sessionId);
if (token.isPresent()) {
String accessToken = token.get().getAccessToken();
logger.trace(String.format("Enriching headers with: Authorization Bearer %s", accessToken));
proxyRequest.setHeader("Authorization", "Bearer " + accessToken);
} else {
logger.info(String.format("No token found in repository for sessionId [%s]", sessionId));
throw new RuntimeException("No token found in repository");
}
}
private void copyBodyFromRequest(HttpServletRequest request, String method, ProxyHttpMethod proxyRequest) throws IOException {
if ("POST".equalsIgnoreCase(method) || "PUT".equalsIgnoreCase(method)) {
String body = request.getReader().lines().collect(Collectors.joining(System.lineSeparator()));
StringEntity entity = new StringEntity(body);
proxyRequest.setEntity(entity);
}
}
private void copyHeadersFromRequest(HttpServletRequest request, ProxyHttpMethod proxyRequest) {
Enumeration<String> headerNames = request.getHeaderNames();
while (headerNames.hasMoreElements()) {
String headerName = headerNames.nextElement();
if (!"host".equalsIgnoreCase(headerName) && !"Content-Length".equalsIgnoreCase(headerName)) {
proxyRequest.setHeader(headerName, request.getHeader(headerName));
}
}
}
private String getSessionId(HttpServletRequest request) {
String sessionId = "";
Cookie[] cookies = request.getCookies();
if(cookies != null){
for (Cookie cookie : cookies) {
if (SESSION_ID_PARAM.equals(cookie.getName())) {
sessionId = cookie.getValue();
}
}
return sessionId;
}
return "";
}
}
不太理想,但我没有看到其他出路
我面临以下问题。我需要在 Websphere 上的 java EE 应用程序 运行ning(没有 Spring)中创建一种方法来将请求代理到另一个位置并使用不记名令牌丰富 header .
举个例子
GET request: http://servicehost.com/proxy/targetapi/userresource
需要转发给
GET request: http://othertargethost.com/targetapi/userresource with Authorization: Bearer randomtoken
我在另一个应用程序中解决了这个问题,但这是一个使用 Netflix Zuul 和 spring-cloud-starter-netflix-zuul 的 spring 启动应用程序。
但是现在我处于严格的 EE 环境中,根本不允许 spring。我没有找到任何关于如何在纯 EE 上下文中设置或配置 netflix zuul 的好的文档或示例。
我还有哪些其他选择可以解决这个问题?我在考虑以下问题
- 在 **/proxy/* 上设置一个 Servlet 并创建一个过滤器来进行转发
- 在 Internet 上搜索类似于 Zuul 的东西,并在 运行 EE 中找到更好的文档
- ...
我真的很感激任何给我指明正确方向的东西。
Jersey web service proxy 对我来说不是解决方案,因为这是在特定端点和特定 http 方法上精确定位的
GET request: http://servicehost.com/proxy/targetapi/userresource
可能是
GET request: http://servicehost.com/proxy/targetapi/contractresource
或
GET request: http://servicehost.com/proxy/specialapi/userresource
并且它需要能够处理 GET、POST、PUT 和 DELETE
我无法在 EE 中使用 Zuul,所以我只有一种方法,那就是编写自己的 servlet
@WebServlet(name = "ProxyServlet", urlPatterns = {"/proxy/*"})
public class ProxyServlet extends HttpServlet {
public static final String SESSION_ID_PARAM = "delijnSessionId";
@Inject
private Logger logger;
@Inject
private ProxyProperties proxyProperties;
@Inject
private SecurityService securityService;
@Inject
private ProxyHttpClientFactory proxyHttpClientFactory;
@Inject
private StreamUtils streamUtils;
@Override
protected void doGet(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws ServletException, IOException {
proxy(httpServletRequest, httpServletResponse);
}
@Override
protected void doPost(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws ServletException, IOException {
proxy(httpServletRequest, httpServletResponse);
}
@Override
protected void doPut(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws ServletException, IOException {
proxy(httpServletRequest, httpServletResponse);
}
@Override
protected void doDelete(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws ServletException, IOException {
proxy(httpServletRequest, httpServletResponse);
}
private void proxy(HttpServletRequest request, HttpServletResponse response) {
try {
String requestUrl = request.getRequestURI();
String method = request.getMethod();
String sessionId = getSessionId(request);
String protocol = proxyProperties.getProperty(ProxyProperties.PROXY_PROTOCOL);
String server = proxyProperties.getProperty(ProxyProperties.PROXY_SERVER);
String port = proxyProperties.getProperty(ProxyProperties.PROXY_PORT);
String newPath = requestUrl.replaceFirst(".*/proxy", "");
URI uri = new URI(protocol, null, server, Integer.parseInt(port), newPath, request.getQueryString(), null);
ProxyHttpMethod proxyRequest = new ProxyHttpMethod(method);
proxyRequest.setURI(uri);
copyBodyFromRequest(request, method, proxyRequest);
copyHeadersFromRequest(request, proxyRequest);
enrichWithAccessToken(proxyRequest, sessionId);
try (CloseableHttpClient client = proxyHttpClientFactory.produce()) {
logger.info("uri [{}]", uri);
logger.info("method [{}]", method);
execute(client, proxyRequest, response);
} catch (IOException e) {
throw new TechnicalException(e);
}
} catch (URISyntaxException | IOException e) {
throw new TechnicalException(e);
}
}
private void execute(CloseableHttpClient client, ProxyHttpMethod proxyHttpMethod, HttpServletResponse response) {
try (CloseableHttpResponse proxyResponse = client.execute(proxyHttpMethod)) {
int statusCode = proxyResponse.getStatusLine().getStatusCode();
if (statusCode >= 200 || statusCode < 300) {
response.setStatus(statusCode);
HttpEntity entity = proxyResponse.getEntity();
if(entity != null){
String result = streamUtils.getStringFromStream(entity.getContent());
logger.trace("result [" + result + "]");
response.getWriter().write(result);
response.getWriter().flush();
response.getWriter().close();
}
} else {
throw new TechnicalException("[" + statusCode + "] Error retrieving access token");
}
} catch (IOException e) {
throw new TechnicalException(e);
}
}
private void enrichWithAccessToken(ProxyHttpMethod proxyRequest, String sessionId) {
Optional<TokenDto> token = securityService.findTokenBySessionIdWithRefresh(sessionId);
if (token.isPresent()) {
String accessToken = token.get().getAccessToken();
logger.trace(String.format("Enriching headers with: Authorization Bearer %s", accessToken));
proxyRequest.setHeader("Authorization", "Bearer " + accessToken);
} else {
logger.info(String.format("No token found in repository for sessionId [%s]", sessionId));
throw new RuntimeException("No token found in repository");
}
}
private void copyBodyFromRequest(HttpServletRequest request, String method, ProxyHttpMethod proxyRequest) throws IOException {
if ("POST".equalsIgnoreCase(method) || "PUT".equalsIgnoreCase(method)) {
String body = request.getReader().lines().collect(Collectors.joining(System.lineSeparator()));
StringEntity entity = new StringEntity(body);
proxyRequest.setEntity(entity);
}
}
private void copyHeadersFromRequest(HttpServletRequest request, ProxyHttpMethod proxyRequest) {
Enumeration<String> headerNames = request.getHeaderNames();
while (headerNames.hasMoreElements()) {
String headerName = headerNames.nextElement();
if (!"host".equalsIgnoreCase(headerName) && !"Content-Length".equalsIgnoreCase(headerName)) {
proxyRequest.setHeader(headerName, request.getHeader(headerName));
}
}
}
private String getSessionId(HttpServletRequest request) {
String sessionId = "";
Cookie[] cookies = request.getCookies();
if(cookies != null){
for (Cookie cookie : cookies) {
if (SESSION_ID_PARAM.equals(cookie.getName())) {
sessionId = cookie.getValue();
}
}
return sessionId;
}
return "";
}
}
不太理想,但我没有看到其他出路