技术笔记:springboot项目使用拦截器实现一个简单的网关请求透传

简介: 技术笔记:springboot项目使用拦截器实现一个简单的网关请求透传

需求:做一个网关将外网的请求做一个转化(添加上签名,格式化等操作),然后将请求转发到内网的网关soul-gateway上


1. 思路:采用拦截器拦截掉请求(我这里是拦截固定前缀的请求),然后做一个请求的转化,最后在拦截器中做response返回


1.1 定义的拦截器 继承 handlerInterceptor接口


package com.tyyd.dyhdzzxxxt.gateway.interceptor;


import com.tyyd.dyhdzzxxxt.gateway.common.AcwsException;


import com.tyyd.dyhdzzxxxt.gateway.config.SoulConfig;


import lombok.extern.slf4j.Slf4j;


import org.springframework.beans.factory.annotation.Autowired;


import org.springframework.http.ResponseEntity;


import org.springframework.stereotype.Component;


import org.springframework.web.servlet.HandlerInterceptor;


import javax.servlet.http.HttpServletRequest;


import javax.servlet.http.HttpServletResponse;


import java.io.IOException;


import java.io.PrintWriter;


@Component


@Slf4j


public class AllRequestHandler implements HandlerInterceptor {


//内网网关的配置 主要是内网地址和端口


@Autowired


SoulConfig soulConfig;


//路由处理请求参数的处理类


@Autowired


RoutingDelegate routingDelegate;


@Override


public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)


throws Exception {


if (log.isDebugEnabled()) {


long logstart = System.currentTimeMillis();


request.setAttribute("logstart", logstart);


}


String URL = "" + soulConfig.getHost() + ":" + soulConfig.getPort();


ResponseEntity responseEntity = routingDelegate.redirect(request, response, URL, "/api/v1");


if (responseEntity == null) {


throw new AcwsException("请求结果异常");


}


response.setStatus(responseEntity.getStatusCodeValue());


response.setCharacterEncoding("UTF-8");


response.setContentType("application/json; charset=utf-8");


PrintWriter out = null;


try {


out = response.getWriter();


out.append(responseEntity.getBody());


} catch (IOException e) {


e.printStackTrace();


} finally {


if (out != null) {


out.close();


}


}


if (log.isDebugEnabled()) {


long logstart = (long) request.getAttribute("logstart");


log.debug("代理请求耗时:{}ms", System.currentTimeMillis() - logstart);


}


return false;


}


}


1.2注入定义的拦截器配置 继承webMvcConfigurer接口


package com.tyyd.dyhdzzxxxt.gateway.interceptor;


import lombok.extern.slf4j.Slf4j;


import org.springframework.beans.factory.annotation.Autowired;


import org.springframework.context.annotation.Configuration;


import org.springframework.web.servlet.config.annotation.InterceptorRegistry;


import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;


@Configuration


@Slf4j


public class IntercepterConfig implements WebMvcConfigurer {


//注入自定义的


@Autowired


private AllRequestHandler addInterceptor;


/


配置拦截路径



@param registry


/


@Override


public void addInterceptors(InterceptorRegistry registry) {


//配置拦截的路径


registry.addInterceptor(addInterceptor).addPathPatterns("/api/v1/");


}


}


1.3 处理请求参数的处理类


package com.tyyd.dyhdzzxxxt.gateway.interceptor;


import com.tyyd.dyhdzzxxxt.gateway.config.SoulAppConfig;


import com.tyyd.dyhdzzxxxt.gateway.config.SoulConfig;


import com.tyyd.dyhdzzxxxt.gateway.domain.AppKeyAndAppSecretEntity;


import com.tyyd.dyhdzzxxxt.gateway.util.SignUtils;


import lombok.extern.slf4j.Slf4j;


import org.springframework.beans.factory.annotation.Autowired;


import org.springframework.http.;


import org.springframework.stereotype.Component;


import org.springframework.util.MultiValueMap;


import org.springframework.util.StreamUtils;


import org.springframework.util.StringUtils;


import org.springframework.web.client.RestTemplate;


import javax.servlet.http.HttpServletRequest;


import javax.servlet.http.HttpServletResponse;


import java.io.IOException;


import java.io.InputStream;


import java.net.URI;


import java.net.URISyntaxException;


import java.util.Collections;


import java.util.List;


import java.util.Map;


@Component


@Slf4j


public class RoutingDelegate {


//内网网关soulgateway的配置 IP地址和端口等


@Autowired


SoulConfig soulConfig;


//考虑分布式部署 每个当前的网关都会有单独的 appkey和appsecret 这里配置的就是appkey和appsecret


@Autowired


SoulAppConfig soulAppConfig;


@Autowired


RestTemplate restTemplate;


public ResponseEntity redirect(HttpServletRequest request, HttpServletResponse response, String routeUrl, String prefix) {


try {


//构造url


String redirectUrl = createRedictUrl(request, routeUrl, prefix);


//构造请求头和请求体


RequestEntity requestEntity = createRequestEntity(request, redirectUrl,prefix);


//转发请求


return route(requestEntity);


} catch (Exception e) {


log.error("请求失败", e);


return new ResponseEntity("请求失败", HttpStatus.INTERNAL_SERVER_ERROR);


}


}


//构造url和路径参数


private String createRedictUrl(HttpServletRequest request, String routeUrl, String prefix) {


String queryString = request.getQueryString();


String url = request.getRequestURI().replaceAll(prefix, "");


return routeUrl + url + (queryString != null ? "?" + queryString : "");


}


//构造请求头和请求体


private RequestEntity createRequestEntity(HttpServletRequest request, String url, String prefix) throws URISyntaxException, //代码效果参考:http://www.jhylw.com.cn/380435929.html

IOException {

String method = request.getMethod();


HttpMethod httpMethod = HttpMethod.resolve(method);


MultiValueMap headers = parseRequestHeader(request, prefix);


byte【】 body = parseRequestBody(request);


return new RequestEntity(body, headers, httpMethod, new URI(url));


}


private ResponseEntity route(RequestEntity requestEntity) {


log.debug("代理访问:{},参数:{}",requestEntity.getUrl(),requestEntity);


ResponseEntity result = restTemplate.exchange(requestEntity, String.class);


log.debug("代理访问:{},结果:{}",requestEntity.getUrl(),result.getBody());


return result;


}


private byte【】 parseRequestBody(HttpServletRequest request) throws IOException {


InputStream inputStream = request.getInputStream();


return //代码效果参考:http://www.jhylw.com.cn/431231091.html

StreamUtils.copyToByteArray(inputStream);

}


private MultiValueMap parseRequestHeader(HttpServletRequest request, String prefix) {


HttpHeaders headers = new HttpHeaders();


List headerNames = Collections.list(request.getHeaderNames());


for (String headerName : headerNames) {


List headerValues = Collections.list(request.getHeaders(headerName));


for (String headerValue : headerValues) {


headers.add(headerName, headerValue);


}


}


String sysId = request.getHeader("sysId");


if(!StringUtils.hasText(sysId)){


sysId = request.getParameter("sysId");


}


    //根据传递过来的sysId来选择不同的appkey可secret


AppKeyAndAppSecretEntity appKeyAndAppSecretEntity = soulAppConfig.getAppKeyAndAppSecretEntity(Integer.valueOf(sysId));


String url = request.getRequestURI().replaceAll(prefix, "");


//构造签名


Map signMap = SignUtils.getInstance().sign(appKeyAndAppSecretEntity, url);


headers.add("sign", signMap.get("sign"));


headers.add("timestamp", signMap.get("timestamp"));


headers.add("version", signMap.get("version"));


headers.add("path", url);


headers.add("appKey", appKeyAndAppSecretEntity.getAppKey());


headers.add("group", soulConfig.getGroup());


headers.add("tag", soulConfig.getTag());


return headers;


}


}


签名工具类Signutils:


package com.tyyd.dyhdzzxxxt.gateway.util;


import com.tyyd.dyhdzzxxxt.gateway.domain.AppKeyAndAppSecretEntity;


import org.springframework.util.DigestUtils;


import java.util.;


import java.util.stream.Collectors;


public final class SignUtils {


private static final SignUtils SIGN_UTILS = new SignUtils();


private SignUtils() {


}


public static SignUtils getInstance() {


return SIGN_UTILS;


}


public static String generateSign(final String signKey, final Map params) {


List storedKeys = Arrays.stream(params.keySet()


.toArray(new String【】{}))


.sorted(Comparator.naturalOrder())


.collect(Collectors.toList());


final String sign = storedKeys.stream()


.filter(key -> !Objects.equals(key, "sign"))


.map(key -> String.join("", key, params.get(key)))


.collect(Collectors.joining()).trim()


.concat(signKey);


return DigestUtils.md5DigestAsHex(sign.getBytes()).toUpperCase();


}


public Map sign(AppKeyAndAppSecretEntity appKeyAndAppSecretEntity , String url){


long now = System.currentTimeMillis();


HashMap params = new HashMap();


//这里要和内网的保持规则相同 如果要改请同时改 否则可能会导致签名校验不通过


//params.put("timestamp", String.valueOf(new Date()));


params.put("timestamp", String.valueOf(now));


params.put("path", url);


params.put("version", "1.0.0");


String sign = generateSign(appKeyAndAppSecretEntity.getAppSecret(), params);


params.put("sign",sign);


return params;


}


}

目录
打赏
0
0
0
0
32
分享
相关文章
SpringBoot项目打war包流程
本文介绍了将Spring Boot项目改造为WAR包并部署到外部Tomcat服务器的步骤。主要内容包括:1) 修改pom.xml中的打包方式为WAR;2) 排除Spring Boot内置的Tomcat依赖;3) 添加Servlet API依赖;4) 改造启动类以支持WAR部署;5) 打包和部署。通过这些步骤,可以轻松地将Spring Boot应用转换为适合外部Tomcat服务器的WAR包。
149 64
SpringBoot项目打war包流程
SpringBoot项目打包成war包
通过上述步骤,我们成功地将一个Spring Boot应用打包成WAR文件,并部署到外部的Tomcat服务器中。这种方式适用于需要与传统Servlet容器集成的场景。
23 8
|
1月前
基于springboot+thymeleaf+Redis仿知乎网站问答项目源码
基于springboot+thymeleaf+Redis仿知乎网站问答项目源码
150 36
SpringBoot start.aliyun.com创建项目,解决properties乱码的问题
通过确保文件和开发环境的编码一致,配置 Maven 编码,设置 Spring Boot 应用和嵌入式服务器的编码,可以有效解决 properties 文件的乱码问题。以上步骤可以帮助开发者确保在 Spring Boot 项目中正确处理和显示多语言字符,避免因编码问题导致的乱码现象。
40 5
java版药品不良反应智能监测系统源码,采用SpringBoot、Vue、MySQL技术开发
基于B/S架构,采用Java、SpringBoot、Vue、MySQL等技术自主研发的ADR智能监测系统,适用于三甲医院,支持二次开发。该系统能自动监测全院患者药物不良反应,通过移动端和PC端实时反馈,提升用药安全。系统涵盖规则管理、监测报告、系统管理三大模块,确保精准、高效地处理ADR事件。
147 1
SpringBoot项目中mysql字段映射使用JSONObject和JSONArray类型
SpringBoot项目中mysql字段映射使用JSONObject和JSONArray类型 图像处理 光通信 分布式计算 算法语言 信息技术 计算机应用
82 8
Spring运维之boot项目多环境(yaml 多文件 proerties)及分组管理与开发控制
通过以上措施,可以保证Spring Boot项目的配置管理在专业水准上,并且易于维护和管理,符合搜索引擎收录标准。
83 2
项目中用的网关Gateway及SpringCloud
Spring Cloud Gateway 是一个功能强大、灵活易用的API网关解决方案。通过配置路由、过滤器、熔断器和限流等功能,可以有效地管理和保护微服务。本文详细介绍了Spring Cloud Gateway的基本概念、配置方法和实际应用,希望能帮助开发者更好地理解和使用这一工具。通过合理使用Spring Cloud Gateway,可以显著提升微服务架构的健壮性和可维护性。
98 0
SpringBoot项目的html页面使用axios进行get post请求
SpringBoot项目的html页面使用axios进行get post请求
54 0
基于SpringBoot+Vue实现的留守儿童爱心网站设计与实现(计算机毕设项目实战+源码+文档)
博主是一位全网粉丝超过100万的CSDN特邀作者、博客专家,专注于Java、Python、PHP等技术领域。提供SpringBoot、Vue、HTML、Uniapp、PHP、Python、NodeJS、爬虫、数据可视化等技术服务,涵盖免费选题、功能设计、开题报告、论文辅导、答辩PPT等。系统采用SpringBoot后端框架和Vue前端框架,确保高效开发与良好用户体验。所有代码由博主亲自开发,并提供全程录音录屏讲解服务,保障学习效果。欢迎点赞、收藏、关注、评论,获取更多精品案例源码。
67 10

热门文章

最新文章

AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等