使用Filter攔截器如何實現請求跨域轉發
Filter攔截器實現請求跨域轉發
因為公司項目需求,項目中前端請求需要通過一個類似中轉的服務轉發(請求在該服務中會重新包裝一些通用參數)
在使用Filter實現轉發後特做一次記錄
package com.unicloud.cce.Filter; import com.alibaba.fastjson.JSON; import com.unicloud.cce.common.RestfulEntity; import com.unicloud.cce.service.CloudosService; import org.apache.commons.io.IOUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.*; import org.springframework.stereotype.Component; import org.springframework.util.AntPathMatcher; import org.springframework.util.StringUtils; import org.springframework.web.client.RestTemplate; import javax.servlet.*; import javax.servlet.annotation.WebFilter; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintWriter; import java.util.*; /** * @author skyxt * Created 2019-06-11 18:46 * Email [email protected] */ @WebFilter(filterName = "authFilter", urlPatterns = { "/*" }) @Component public class RequestFilter implements Filter { //該處配置需要轉發的路徑 public static final Set<String> FILTER_URL = Collections.unmodifiableSet(new HashSet<>(Arrays.asList( "/config/*" ))); @Autowired private RestTemplate restTemplate; @Autowired private CloudosService cloudosService; private final static Logger logger = LoggerFactory.getLogger(RequestFilter.class); @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { if (!(request instanceof HttpServletRequest) || !(response instanceof HttpServletResponse)) { return; } HttpServletRequest req = (HttpServletRequest) request; HttpServletResponse rsp = (HttpServletResponse) response; AntPathMatcher matcher = new AntPathMatcher(); Optional<String> cloudIp = Optional.empty(); // for (String url : FILTER_URL) { // if (matcher.match(url, req.getRequestURI().substring(req.getContextPath().length()))) { // cloudIp = cloudosService.cloudosList("", "").stream().filter(cloudos -> // cloudos.getId().equals(((HttpServletRequest) request).getHeader("cloudId")) // ).map(Cloudos::getCloudIp).findFirst(); // } // } cloudIp = Optional.of("localhost"); if (cloudIp.isPresent()) { switch (req.getMethod()) { case "GET": { request(req, rsp, HttpMethod.GET, cloudIp.get()); break; } case "POST": { request(req, rsp, HttpMethod.POST, cloudIp.get()); break; } case "PUT": { request(req, rsp, HttpMethod.PUT, cloudIp.get()); break; } case "PATCH": { request(req, rsp, HttpMethod.PATCH, cloudIp.get()); break; } case "DELETE": { request(req, rsp, HttpMethod.DELETE, cloudIp.get()); break; } default:{ logger.error("unknow request method:" + req.getMethod()); rsp.setCharacterEncoding("UTF-8"); try (PrintWriter out = rsp.getWriter()) { out.write("請求方法未知"); } catch (Exception e1) { logger.error(e1.getMessage() + e1); } } } } else { chain.doFilter(request, response); } } @Override public void destroy() { } private void request(HttpServletRequest req, HttpServletResponse rsp, HttpMethod method, String cloudIp) throws IOException { rsp.setCharacterEncoding("UTF-8"); String requestBody = IOUtils.toString(req.getInputStream(), "UTF-8"); Object body = null; if (StringUtils.hasText(requestBody)) { body = JSON.parse(requestBody); } HttpHeaders headers = new HttpHeaders(); Enumeration<String> headerNames = req.getHeaderNames(); while (headerNames.hasMoreElements()) { String name = headerNames.nextElement(); headers.add(name, req.getHeader(name)); } String url; if (StringUtils.hasText(req.getQueryString())) { url = String.format( "http://%s:15120%s?%s", cloudIp, req.getRequestURI().substring(req.getContextPath().length()), req.getQueryString() ); } else { url = String.format( "http://%s:15120%s", cloudIp, req.getRequestURI().substring(req.getContextPath().length()) ); } HttpEntity<Object> httpEntity = new HttpEntity<>(body, headers); ResponseEntity<RestfulEntity> exchange = null; try { exchange = restTemplate.exchange( url, method, httpEntity, RestfulEntity.class ); } catch (Exception e) { logger.error(e.getMessage(), e); try (PrintWriter out = rsp.getWriter()) { out.write("請求異常"); } catch (Exception e1) { logger.error(e1.getMessage() + e1); } } if (exchange != null) { exchange.getStatusCode(); rsp.setStatus(exchange.getStatusCodeValue()); exchange.getHeaders().entrySet().stream().forEach(entry -> { String value = entry.getValue().toString(); rsp.addHeader(entry.getKey(), value.substring(1, value.length()-1)); }); try (PrintWriter out = rsp.getWriter()) { out.write(JSON.toJSONString(exchange.getBody())); } catch (Exception e) { logger.error(e.getMessage(), e); } } else { logger.info("error: URL:" + "http://" + cloudIp + ":15120" + req.getRequestURI().substring(req.getContextPath().length())); try (PrintWriter out = rsp.getWriter()) { out.write("請求異常"); } catch (Exception e1) { logger.error(e1.getMessage() + e1); } } } }
使用filter解決跨域
在web.xml配置攔截器
<filter> <filter-name>servletFilterTest</filter-name> <filter-class>cn.test.intercepter.ServletFilterTest</filter-class> </filter> <filter-mapping> <filter-name>servletFilterTest</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
過濾器代碼
import org.springframework.web.bind.annotation.RequestMethod; import javax.servlet.*; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; public class ServletFilterTest implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest; httpServletRequest.getSession(); HttpServletResponse httpResponse = (HttpServletResponse) servletResponse; httpResponse.setHeader("Access-Control-Allow-Origin", "*"); httpResponse.setHeader("Access-Control-Allow-Methods", "*"); httpResponse.setHeader("Access-Control-Max-Age", "3600"); httpResponse.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Connection, User-Agent, Cookie"); httpResponse.setHeader("Access-Control-Allow-Credentials", "true"); httpResponse.setHeader("Content-type", "application/json"); httpResponse.setHeader("Cache-Control", "no-cache, must-revalidate"); if (httpServletRequest.getMethod().equals(RequestMethod.OPTIONS.name())) { return ; } filterChain.doFilter(httpServletRequest, httpResponse); } @Override public void destroy() { } }
以上為個人經驗,希望能給大傢一個參考,也希望大傢多多支持WalkonNet。
推薦閱讀:
- CorsFilter 過濾器解決跨域的處理
- SpringBoot中使用Servlet三大組件的方法(Servlet、Filter、Listener)
- JavaWeb中請求轉發和請求重定向的區別以及使用
- Spring Security之默認的過濾器鏈及自定義Filter操作
- SpringBoot 請求參數忽略大小寫的實例