创作大赛

gateway 网关(转发,跨域,拦截器等)

1,所需依赖

org.springframework.cloud

spring-cloud-starter-gateway

2,配置路径映射

spring:

cloud:

gateway:

discovery:

locator:

# 开启项目名称映射功能,即通过服务名访问项目,不需要写明具体IP地址

enabled: true

# 请求路由全部转小写字母,如 Aa/Bb 会被转为 aa/bb

lower-case-service-id: true

routes:

# 路由规则的唯一标识,任意齐名,建议和服务名一致

- id: sc-web-admin-back

# 转发到的节点,lb:// 为 http,lb:ws:// 为 websocket

uri: lb://sc-web-admin-back/

predicates:

# 断言规则,这里设置匹配的路由规则

- Path=/admin-back/**

# 过滤规则

filters:

# 转发到具体项目去掉路由首单词,如 /admin-back/a 转发为 /a

- StripPrefix=1

如上,便配置了一个接管以 admin-back 开头的路由,并转发给项目 sc-web-admin-back

3,跨域配置

spring:

cloud:

gateway:

globalcors:

# 全局允许跨域访问

cors-configurations:

'[/**]':

allow-credentials: true

allowed-origins: "*"

allowed-headers: "*"

allowed-methods:

- OPTIONS

- GET

- POST

- PUT

- DELETE

4,全局异常处理

日常开发中,我们难免会有忘记处理的异常,程序也很难保重不出错,这时候我们就需要一个能够全局捕捉异常的功能来未我们兜底,防止错误被用户看到影响体验

package com.hwq.gateway.handler;

import com.fasterxml.jackson.core.JsonProcessingException;

import com.fasterxml.jackson.databind.ObjectMapper;

import com.hwq.gateway.vo.ResultVO;

import lombok.extern.slf4j.Slf4j;

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

import org.springframework.context.annotation.Primary;

import org.springframework.core.Ordered;

import org.springframework.core.annotation.Order;

import org.springframework.http.HttpStatus;

import org.springframework.http.server.reactive.ServerHttpResponse;

import org.springframework.stereotype.Component;

import org.springframework.web.server.ResponseStatusException;

import org.springframework.web.server.ServerWebExchange;

import org.springframework.web.server.WebExceptionHandler;

import reactor.core.publisher.Mono;

@Component

@Primary // 同类型带有该注解的 Bean 优先背识别

@Order(Ordered.HIGHEST_PRECEDENCE)

@Slf4j

public class JsonExceptionHandler implements WebExceptionHandler {

@Autowired

private ObjectMapper objectMapper;

/**

* 所有异常都会在这里被集中处理

* @param exchange 上下文

* @param ex 异常

* SuppressWarnings("NullableProblems"):屏蔽 @NonNullApi 的警告

*/

@Override

@SuppressWarnings("NullableProblems")

public Mono handle(ServerWebExchange exchange, Throwable ex) {

ServerHttpResponse response = exchange.getResponse();

ResultVO vo;

if (ex instanceof ResponseStatusException && ((ResponseStatusException) ex).getStatus() == HttpStatus.NOT_FOUND) {

vo = ResultVO.fail("当前访问的地址不存在,请修改后重试!");

} else {

vo = ResultVO.error(ex.getMessage());

}

return response.writeWith(Mono.fromSupplier(() -> {

byte[] bytes;

try {

bytes = objectMapper.writeValueAsBytes(vo);

} catch (JsonProcessingException e) {

response.setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR);

bytes = "JSON 转换异常!".getBytes();

}

return response.bufferFactory().wrap(bytes);

}));

}

}

5,捕获转发项目传来的异常

上面的类只能捕捉网关本身发生的异常,而如果其调用(转发)的项目发生异常,返回错误时不能拦截,这时候我们就需要一个过滤器,能把哪些错误的返回拦截掉,并触发上面全局异常处理

package com.hwq.gateway.filter;

import org.reactivestreams.Publisher;

import org.springframework.cloud.gateway.filter.GatewayFilterChain;

import org.springframework.cloud.gateway.filter.GlobalFilter;

import org.springframework.core.Ordered;

import org.springframework.core.io.buffer.DataBuffer;

import org.springframework.core.io.buffer.DataBufferUtils;

import org.springframework.http.HttpStatus;

import org.springframework.http.server.reactive.ServerHttpResponse;

import org.springframework.http.server.reactive.ServerHttpResponseDecorator;

import org.springframework.stereotype.Component;

import org.springframework.web.server.ResponseStatusException;

import org.springframework.web.server.ServerWebExchange;

import reactor.core.publisher.Flux;

import reactor.core.publisher.Mono;

import java.nio.charset.StandardCharsets;

@Component

public class ExceptionFilter implements Ordered, GlobalFilter {

/**

* 如果需要拦截返回值并处理,这里则需要返回负数

*/

@Override

public int getOrder() {

return -1;

}

/**

* 异常拦截,拦截响应值不是 200 的数据,并抛给全局异常处理

*/

@Override

@SuppressWarnings({"unchecked", "NullableProblems"})

public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {

ServerHttpResponse response = exchange.getResponse();

ServerHttpResponseDecorator decorated = new ServerHttpResponseDecorator(response) {

@Override

public Mono writeWith(Publisher body) {

if (body instanceof Flux) {

Flux fluxBody = (Flux) body;

return super.writeWith(fluxBody.map(dataBuffer -> {

if (response.getStatusCode() == HttpStatus.NOT_FOUND) {

throw new ResponseStatusException(HttpStatus.NOT_FOUND);

}

if (response.getStatusCode() != HttpStatus.OK) {

byte[] content = new byte[dataBuffer.readableByteCount()];

dataBuffer.read(content);

DataBufferUtils.release(dataBuffer); // 释放掉内存

String errMsg = new String(content, StandardCharsets.UTF_8);

throw new RuntimeException(errMsg);

}

return dataBuffer;

}));

}

return super.writeWith(body);

}

};

return chain.filter(exchange.mutate().response(decorated).build());

}

}

6,普通的过滤器

package com.hwq.gateway.filter;

import org.springframework.cloud.gateway.filter.GatewayFilterChain;

import org.springframework.cloud.gateway.filter.GlobalFilter;

import org.springframework.core.Ordered;

import org.springframework.http.server.reactive.ServerHttpRequest;

import org.springframework.http.server.reactive.ServerHttpResponse;

import org.springframework.stereotype.Component;

import org.springframework.web.server.ServerWebExchange;

import reactor.core.publisher.Mono;

@Component

public class UserFilter implements Ordered, GlobalFilter {

/**

* 这里的返回值决定拦截器的优先级,数字越小越先被触发,支持负数

*/

@Override

public int getOrder() {

return 1;

}

@Override

public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {

// 这里可以获取 请求对象 和 响应对象

ServerHttpRequest request = exchange.getRequest();

ServerHttpResponse response = exchange.getResponse();

// 逻辑处理

// 逻辑处理

// 传递给下一级别的过滤器

return chain.filter(exchange);

}

}

Copyright © 2088 承德书写游戏活动中心 - 剧情创作专属天地 All Rights Reserved.
友情链接