转发请求到外部api
#253
Replies: 3 comments 4 replies
-
没什么思路。这种应该现成的解决方案很多吧,直接用这些不挺好的。 |
Beta Was this translation helpful? Give feedback.
2 replies
-
package me.zhengjie.aspect;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import me.zhengjie.annotation.Forward;
import me.zhengjie.exception.BadRequestException;
import me.zhengjie.utils.RequestHolder;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.*;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StreamUtils;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.ContentCachingRequestWrapper;
import org.springframework.web.util.UriComponents;
import org.springframework.web.util.UriComponentsBuilder;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.lang.reflect.Method;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.util.*;
@Aspect
@Component
public class ForwardAspect {
private final RestTemplate restTemplate;
private static final Logger log = LoggerFactory.getLogger(ForwardAspect.class);
private static final ObjectMapper objectMapper = new ObjectMapper();
public ForwardAspect(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
@Pointcut("@annotation(me.zhengjie.annotation.Forward)")
public void pointcut() {
}
@Around("pointcut()")
public ResponseEntity<String> around(ProceedingJoinPoint joinPoint) {
try {
// 动态获取注解变量
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method signatureMethod = signature.getMethod();
Forward forward = signatureMethod.getAnnotation(Forward.class);
String url = forward.url();
// 根据原始请求容器获取请求的 Body 数据 -- form表单或body数据
HttpServletRequest request = RequestHolder.getHttpServletRequest();
String body = getRequestData(request).toString();
log.error(body);
// 获取请求查询数据
String query = request.getQueryString();
// log.error(query);
// 设置请求头部并显式设置 json 头
HttpHeaders headers = new ServletServerHttpRequest(request).getHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
// 获取原始请求方法
String method = request.getMethod();
HttpMethod httpMethod = HttpMethod.resolve(method);
if (httpMethod == null) {
httpMethod = HttpMethod.POST;
}
// 动态实例化 httpEntity 对象
HttpEntity<String> httpEntity;
if (HttpMethod.GET.equals(httpMethod) || HttpMethod.DELETE.equals(httpMethod)) {
UriComponents uriComponents = UriComponentsBuilder.fromUriString(url).query(query).build();
URI uri = uriComponents.toUri();
httpEntity = new HttpEntity<>(headers);
url = uri.toString();
} else {
httpEntity = new HttpEntity<>(body, headers);
}
// 动态转发请求到外部接口
return restTemplate.exchange(url, httpMethod, httpEntity, String.class);
} catch (Exception e) {
throw new BadRequestException("代理转发请求异常:" + e.getMessage());
}
}
public Map<String, Object> getRequestData(HttpServletRequest request) throws IOException {
ContentCachingRequestWrapper requestWrapper = new ContentCachingRequestWrapper(request);
String contentType = requestWrapper.getContentType();
if (contentType != null) {
if (contentType.equalsIgnoreCase("application/json")) {
String requestBody = StreamUtils.copyToString(requestWrapper.getInputStream(), StandardCharsets.UTF_8);
if (!requestBody.isEmpty()) {
return parseJsonBody(requestBody);
}
return Collections.emptyMap();
} else if (contentType.equalsIgnoreCase("application/x-www-form-urlencoded")) {
MultiValueMap<String, String> formParams = new LinkedMultiValueMap<>(parseParamsMap(requestWrapper.getParameterMap()));
Map<String, Object> formParamsMap = new HashMap<>();
for (String key : formParams.keySet()) {
formParamsMap.put(key, formParams.getFirst(key));
}
return formParamsMap;
} else if (contentType.equalsIgnoreCase("multipart/form-data")) {
throw new BadRequestException("暂不支持请求头:" + contentType);
}
}
return Collections.emptyMap();
}
private Map<String, Object> parseJsonBody(String requestBody) throws IOException {
return objectMapper.readValue(requestBody, new TypeReference<Map<String, Object>>() {
});
}
private Map<String, List<String>> parseParamsMap(Map<String, String[]> paramsMap) {
Map<String, List<String>> hashMap = new HashMap<>();
for (Map.Entry<String, String[]> entry : paramsMap.entrySet()) {
String key = entry.getKey();
String[] values = entry.getValue();
hashMap.put(key, Arrays.asList(values));
}
return hashMap;
}
} 现在没办法读取到 form 表单请求数据,我想用注解的形式去调用,用 gateway 心智负担比较大 |
Beta Was this translation helpful? Give feedback.
0 replies
-
大佬可以帮忙修改下嘛 |
Beta Was this translation helpful? Give feedback.
2 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
-
你好,可以帮忙实现转发请求到外部接口吗?希望通过注解形式拦截请求,自动解析原有请求方法,参数和响应。如果有异常抛出
Beta Was this translation helpful? Give feedback.
All reactions