马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
x
目录
媒介:想实现一个轻量级的接口反向代理和转发的一个接口服务,可以通过这个服务做一些须要认证才华访问的接口给到前端利用,这样就实现了一种认证可以调用多种第三方体系的服务。
基本逻辑就是将请求的请求方式、请求头、请求体提取出来,将这些信息转发到别的一个接口
- import org.springframework.boot.context.properties.ConfigurationProperties;
- import org.springframework.context.annotation.Configuration;
- import org.springframework.stereotype.Component;
- import java.util.List;
- /**
- * 路由代理配置
- */
- @Configuration
- @ConfigurationProperties(prefix = "delegate.config.api", ignoreUnknownFields = false)
- public class RouterDelegateProperties {
- /**
- * 网关地址
- */
- String rootPath;
- /**
- * 服务名称, 服务名称和服务网关和服务拓展器一一对应, 服务网关和服务拓展器没有则用default代替
- */
- List<String> serviceName;
- /**
- * 服务网关, 服务名称和服务网关和服务拓展器一一对应, 服务网关和服务拓展器没有则用default代替
- */
- List<String> serviceRoot;
- /**
- * 服务拓展器, 服务名称和服务网关和服务拓展器一一对应, 服务网关和服务拓展器没有则用default代替
- */
- List<String> serviceExtractor;
- public String getRootPath() {
- return rootPath;
- }
- public void setRootPath(String rootPath) {
- this.rootPath = rootPath;
- }
- public List<String> getServiceName() {
- return serviceName;
- }
- public void setServiceName(List<String> serviceName) {
- this.serviceName = serviceName;
- }
- public List<String> getServiceRoot() {
- return serviceRoot;
- }
- public void setServiceRoot(List<String> serviceRoot) {
- this.serviceRoot = serviceRoot;
- }
- public List<String> getServiceExtractor() {
- return serviceExtractor;
- }
- public void setServiceExtractor(List<String> serviceExtractor) {
- this.serviceExtractor = serviceExtractor;
- }
- }
复制代码
- import java.io.Serializable;
- /**
- * 代理路由配置 DTO
- */
- public class RouterDelegateConfigDTO implements Serializable {
- private static final long serialVersionUID = 1L;
- /**
- * 网关地址
- */
- private String rootPath;
- /**
- * 服务名称
- */
- private String serviceName;
- /**
- * 服务名称地址
- */
- private String serviceRoot;
- /**
- * 服务名称处理器
- */
- private String serviceExtractor;
- public String getRootPath() {
- return rootPath;
- }
- public void setRootPath(String rootPath) {
- this.rootPath = rootPath;
- }
- public String getServiceName() {
- return serviceName;
- }
- public void setServiceName(String serviceName) {
- this.serviceName = serviceName;
- }
- public String getServiceRoot() {
- return serviceRoot;
- }
- public void setServiceRoot(String serviceRoot) {
- this.serviceRoot = serviceRoot;
- }
- public String getServiceExtractor() {
- return serviceExtractor;
- }
- public void setServiceExtractor(String serviceExtractor) {
- this.serviceExtractor = serviceExtractor;
- }
- }
复制代码
- import org.springframework.http.HttpHeaders;
- import zsoft.gov.datacenter.biztable.common.dto.router.RouterDelegateConfigDTO;
- import javax.servlet.http.HttpServletRequest;
- /**
- * 路由代理拓展器
- */
- public interface RouterDelegateExtractor {
- /**
- * 处理请求url, 返回null则使用通用处理逻辑
- *
- * @param request 请求体对象
- * @param configDTO 服务配置对象
- * @param prefix 代理前缀
- * @return
- */
- String getRequestRootUrl(HttpServletRequest request, RouterDelegateConfigDTO configDTO, String prefix);
- /**
- * 处理请求头
- *
- * @param request 请求体对象
- * @param headers 请求头
- */
- void parseRequestHeader(HttpServletRequest request, HttpHeaders headers);
- /**
- * 处理请求体, 返回null则使用通用处理逻辑
- *
- * @param request 请求体对象
- * @return
- */
- byte[] parseRequestBody(HttpServletRequest request);
- }
复制代码
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.beans.factory.annotation.Qualifier;
- import org.springframework.context.annotation.Bean;
- import org.springframework.context.annotation.Configuration;
- import org.springframework.http.client.ClientHttpRequestFactory;
- import org.springframework.http.client.ClientHttpResponse;
- import org.springframework.http.client.SimpleClientHttpRequestFactory;
- import org.springframework.http.converter.HttpMessageConverter;
- import org.springframework.http.converter.StringHttpMessageConverter;
- import org.springframework.web.client.DefaultResponseErrorHandler;
- import org.springframework.web.client.RestTemplate;
- import java.io.IOException;
- import java.nio.charset.Charset;
- import java.util.List;
- @Configuration
- public class FetchApiRestTemplateConfig {
- @Bean({"fetchApiRestTemplate"})
- @Autowired
- public RestTemplate restTemplate(@Qualifier("fetchApiClientHttpRequestFactory") ClientHttpRequestFactory factory) {
- RestTemplate restTemplate = new RestTemplate(factory);
- restTemplate.setErrorHandler(new DefaultResponseErrorHandler() {
- @Override
- public void handleError(ClientHttpResponse response) throws IOException {
- // if (response.getRawStatusCode() != 401 && response.getRawStatusCode() != 404) {
- // super.handleError(response);
- // }
- // 处理返回 4xx 的状态码时不抛出异常
- if (!response.getStatusCode().is4xxClientError()) {
- super.handleError(response);
- }
- }
- });
- // 中文乱码问题
- List<HttpMessageConverter<?>> httpMessageConverters = restTemplate.getMessageConverters();
- httpMessageConverters.stream().forEach(httpMessageConverter -> {
- if (httpMessageConverter instanceof StringHttpMessageConverter) {
- StringHttpMessageConverter messageConverter = (StringHttpMessageConverter) httpMessageConverter;
- messageConverter.setDefaultCharset(Charset.forName("UTF-8"));
- }
- });
- return restTemplate;
- }
- @Bean({"fetchApiClientHttpRequestFactory"})
- public ClientHttpRequestFactory simpleClientHttpRequestFactory() {
- SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
- factory.setReadTimeout(1000 * 50); // 读取超时(毫秒)
- factory.setConnectTimeout(1000 * 10); // 连接超时(毫秒)
- return factory;
- }
- }
复制代码
- import org.apache.commons.collections.CollectionUtils;
- import org.apache.commons.lang3.StringUtils;
- import org.slf4j.Logger;
- import org.slf4j.LoggerFactory;
- import org.springframework.beans.factory.annotation.Qualifier;
- import org.springframework.boot.ApplicationArguments;
- import org.springframework.boot.ApplicationRunner;
- import org.springframework.http.*;
- import org.springframework.stereotype.Service;
- import org.springframework.util.StreamUtils;
- import org.springframework.web.client.RestTemplate;
- import zsoft.gov.datacenter.biztable.common.config.RouterDelegateProperties;
- import zsoft.gov.datacenter.biztable.common.dto.router.RouterDelegateConfigDTO;
- import zsoft.gov.datacenter.biztable.common.response.Result;
- import javax.annotation.Resource;
- 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;
- import java.util.concurrent.ConcurrentHashMap;
- /**
- * 路由代理
- */
- @Service
- public class RouterDelegate implements ApplicationRunner {
- protected Logger logger = LoggerFactory.getLogger(getClass());
- private static Map<String, RouterDelegateConfigDTO> configMap;
- @Resource
- @Qualifier("fetchApiRestTemplate")
- private RestTemplate restTemplate;
- @Resource
- private RouterDelegateProperties properties;
- @Resource
- private Map<String, RouterDelegateExtractor> stringRouterDelegateExtractorMap;
- /**
- * 初始化配置类
- *
- * @param args
- * @throws Exception
- */
- @Override
- public void run(ApplicationArguments args) throws Exception {
- boolean intiFlag = false;
- logger.info(">>> -----开始初始化路由代理配置类!");
- /**
- * 最终configMap效果
- * {
- * 服务名称: {
- * rootPath: "系统网关地址",
- * serviceName: "服务名称",
- * serviceRoot: "服务网关",
- * serviceExtractor: "服务拓展器",
- * }
- * }
- */
- String rootPath = properties.getRootPath();
- List<String> serviceName = properties.getServiceName();
- List<String> serviceRoot = properties.getServiceRoot();
- List<String> serviceExtractor = properties.getServiceExtractor();
- // 服务名称, 服务名称和服务网关和服务处理器一一对应, 如果没有对应的服务网关和服务处理器, 则用英文逗号隔开
- if (StringUtils.isNotBlank(rootPath)
- && CollectionUtils.isNotEmpty(serviceName)
- && CollectionUtils.isNotEmpty(serviceExtractor)
- && CollectionUtils.isNotEmpty(serviceRoot)
- && serviceName.size() == serviceRoot.size()
- && serviceName.size() == serviceExtractor.size()) {
- intiFlag = true;
- // 初始化大小避免扩容
- int initialCapacity = (int) (serviceName.size() / 0.75) + 1;
- configMap = new ConcurrentHashMap<>(initialCapacity);
- for (int i = 0; i < serviceName.size(); i++) {
- RouterDelegateConfigDTO dto = new RouterDelegateConfigDTO();
- String serName = serviceName.get(i);
- dto.setRootPath(rootPath);
- dto.setServiceName(serName);
- // default 是占位符, 配置成default相当于没有配置
- dto.setServiceRoot("default".equals(serviceRoot.get(i)) ? null : serviceRoot.get(i));
- dto.setServiceExtractor("default".equals(serviceExtractor.get(i)) ? null : serviceExtractor.get(i));
- configMap.put(serName, dto);
- }
- }
- if (intiFlag) logger.info(">>> 初始化路由代理配置类成功!");
- else logger.error(">>> 初始化路由代理配置类失败!");
- }
- public ResponseEntity<byte[]> redirect(HttpServletRequest request, HttpServletResponse response, String prefix, String serviceName) {
- String requestURI = request.getRequestURI();
- RouterDelegateConfigDTO currentConfig = getCurrentServiceConfig(serviceName);
- if (currentConfig == null) {
- return buildErrorResponseEntity("SERVICE ERROR! 服务不存在!", HttpStatus.NOT_FOUND);
- }
- RouterDelegateExtractor extractorCallBack = getRouterDelegateExtractor(serviceName);
- try {
- // 创建url
- String redirectUrl = createRequestUrl(request, currentConfig, prefix, extractorCallBack);
- logger.info(">>> redirectUrl代理后的完整地址: [{}]", redirectUrl);
- RequestEntity requestEntity = createRequestEntity(request, redirectUrl, extractorCallBack);
- // return route(request, redirectUrl, extractorCallBack);
- ResponseEntity<byte[]> result = route(requestEntity);
- if (result.getHeaders() != null && result.getHeaders().containsKey(HttpHeaders.TRANSFER_ENCODING)) {
- // 移除响应头 Transfer-Encoding, 因为高版本的nginx会自动添加该响应头, 多个响应值nginx会报错
- // 多个响应值nginx报错: *6889957 upstream sent duplicate header line: "Transfer-Encoding: chunked", previous value: "Transfer-Encoding: chunked" while reading response header from upstream
- HttpHeaders headers = HttpHeaders.writableHttpHeaders(result.getHeaders());
- headers.remove(HttpHeaders.TRANSFER_ENCODING);
- }
- //logger.info(">>> [{}] 代理成功, 请求耗时: [{}]", requestURI, System.currentTimeMillis() - l1);
- return result;
- } catch (Exception e) {
- logger.error("REDIRECT ERROR", e);
- //logger.error(">>> [{}] 代理失败, 请求耗时: [{}]", requestURI, System.currentTimeMillis() - l1);
- return buildErrorResponseEntity("REDIRECT ERROR! " + e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
- }
- }
- private ResponseEntity buildErrorResponseEntity(String msg, HttpStatus httpStatus) {
- HttpHeaders headers = new HttpHeaders();
- headers.setContentType(MediaType.APPLICATION_JSON);
- Result body = Result.build(httpStatus.value(), msg);
- return new ResponseEntity(body, headers, httpStatus);
- }
- /**
- * 获取当前服务配置
- *
- * @param serviceName
- * @return
- */
- public RouterDelegateConfigDTO getCurrentServiceConfig(String serviceName) {
- if (configMap == null || !configMap.containsKey(serviceName)) {
- return null;
- }
- return configMap.get(serviceName);
- }
- /**
- * 获取当前路由服务拓展器
- *
- * @param serviceName
- * @return
- */
- private RouterDelegateExtractor getRouterDelegateExtractor(String serviceName) {
- RouterDelegateConfigDTO currentConfig = getCurrentServiceConfig(serviceName);
- if (currentConfig == null) {
- return null;
- }
- String serviceExtractor = currentConfig.getServiceExtractor();
- if (StringUtils.isBlank(serviceExtractor)) {
- return null;
- }
- RouterDelegateExtractor extractor = stringRouterDelegateExtractorMap.get(serviceExtractor + "RouterDelegateExtractor");
- return extractor;
- }
- /**
- * 创建请求地址
- *
- * @param request
- * @param configDTO
- * @param prefix
- * @param extractorCallback
- * @return
- */
- private String createRequestUrl(HttpServletRequest request, RouterDelegateConfigDTO configDTO, String prefix, RouterDelegateExtractor extractorCallback) {
- String routeUrl = configDTO.getRootPath();
- // 拓展器不为null, 并且有返回结果才使用
- if (extractorCallback != null) {
- String hostUrl = extractorCallback.getRequestRootUrl(request, configDTO, prefix);
- if (hostUrl != null) routeUrl = hostUrl;
- }
- String queryString = request.getQueryString();
- // return routeUrl + request.getRequestURI().replace(prefix, "") +
- // (queryString != null ? "?" + queryString : "");
- // request.getRequestURI() 包括 server.servlet.context-path
- // request.getServletPath() 不包括 server.servlet.context-path
- // http://127.0.0.1/databook-api/graphdb/sj/tianda/openapi/v1/applets?name=ts
- // request.getRequestURI() = /databook-api/graphdb/sj/tianda/openapi/v1/applets
- // request.getServletPath() = /graphdb/sj/tianda/openapi/v1/applets
- String serviceName = configDTO.getServiceName();
- return routeUrl + request.getServletPath().replaceFirst(prefix + "/" + serviceName, "") +
- (queryString != null ? "?" + queryString : "");
- }
- private RequestEntity createRequestEntity(HttpServletRequest request, String url, RouterDelegateExtractor extractorCallBack) throws URISyntaxException, IOException {
- String method = request.getMethod();
- HttpMethod httpMethod = HttpMethod.resolve(method);
- HttpHeaders headers = parseRequestHeader(request, extractorCallBack);
- byte[] body = parseRequestBody(request, extractorCallBack);
- return new RequestEntity<>(body, headers, httpMethod, new URI(url));
- }
- private ResponseEntity<byte[]> route(HttpServletRequest request, String url, RouterDelegateExtractor extractorCallBack) throws IOException, URISyntaxException {
- String method = request.getMethod();
- HttpMethod httpMethod = HttpMethod.resolve(method);
- HttpHeaders headers = parseRequestHeader(request, extractorCallBack);
- byte[] body = parseRequestBody(request, extractorCallBack);
- // 设置请求实体
- HttpEntity<byte[]> httpEntity = new HttpEntity<>(body, headers);
- URI uri = new URI(url);
- return restTemplate.exchange(uri, httpMethod, httpEntity, byte[].class);
- }
- private ResponseEntity<byte[]> route(RequestEntity requestEntity) {
- return restTemplate.exchange(requestEntity, byte[].class);
- }
- /**
- * 处理请求头
- *
- * @param request
- * @param extractorCallBack
- * @return
- */
- private HttpHeaders parseRequestHeader(HttpServletRequest request, RouterDelegateExtractor extractorCallBack) {
- List<String> headerNames = Collections.list(request.getHeaderNames());
- HttpHeaders headers = new HttpHeaders();
- for (String headerName : headerNames) {
- List<String> headerValues = Collections.list(request.getHeaders(headerName));
- for (String headerValue : headerValues) {
- headers.add(headerName, headerValue);
- }
- }
- if (extractorCallBack != null) {
- extractorCallBack.parseRequestHeader(request, headers);
- }
- // 移除请求头accept-encoding, 不移除会导致响应体转成String时会乱码
- headers.remove("accept-encoding");
- return headers;
- }
- /**
- * 处理请求体
- *
- * @param request
- * @param extractorCallBack
- * @return
- * @throws IOException
- */
- private byte[] parseRequestBody(HttpServletRequest request, RouterDelegateExtractor extractorCallBack) throws IOException {
- // 拓展器不为null, 并且返回的结果也不为null才使用返回结果, 否则使用通用处理逻辑
- if (extractorCallBack != null) {
- byte[] body = extractorCallBack.parseRequestBody(request);
- if (body != null) return body;
- }
- InputStream inputStream = request.getInputStream();
- return StreamUtils.copyToByteArray(inputStream);
- }
- }
复制代码
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.http.ResponseEntity;
- import org.springframework.web.bind.annotation.PathVariable;
- import org.springframework.web.bind.annotation.RequestMapping;
- import org.springframework.web.bind.annotation.RequestMethod;
- import org.springframework.web.bind.annotation.RestController;
- import zsoft.gov.datacenter.biztable.common.router.RouterDelegate;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- /**
- * 路由代理接口
- */
- @RestController
- @RequestMapping
- public class RouterDelegateController {
- public final static String DELEGATE_PREFIX = "/delegate";
- @Autowired
- private RouterDelegate routerDelegate;
- /**
- * 路由代理接口
- *
- * @param serviceName
- * @param request
- * @param response
- * @return
- */
- @RequestMapping(value = DELEGATE_PREFIX + "/{serviceName}/**", method = {RequestMethod.GET, RequestMethod.POST, RequestMethod.PUT, RequestMethod.DELETE})
- public ResponseEntity redirect(@PathVariable("serviceName") String serviceName, HttpServletRequest request, HttpServletResponse response) {
- return routerDelegate.redirect(request, response, DELEGATE_PREFIX, serviceName);
- }
- }
复制代码
- #路由代理配置-网关地址
- delegate.config.api.rootPath=http://192.168.50.43:7612
- #路由代理配置-服务名称, 服务名称和服务网关和服务拓展器一一对应, 服务网关和服务拓展器没有则用default代替
- delegate.config.api.serviceName=common,csdn
- #路由代理配置-服务网关, 服务名称和服务网关和服务拓展器一一对应, 服务网关和服务拓展器没有则用default代替
- delegate.config.api.serviceRoot=default,https://csdn.net
- #路由代理配置-服务拓展器, 服务名称和服务网关和服务拓展器一一对应, 服务网关和服务拓展器没有则用default代替
- delegate.config.api.serviceExtractor=default,csdnBlog
复制代码 免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |