2022-11-02
過濾器 請求
Filter過濾器
gateway中過濾器主要分為網關(路由)過濾器和全局過濾器兩個,網關(路由)過濾器主要是個某個服務指定的過濾器,全局過濾器主要是給所有的路由設置的
4.1 網關過濾器
網關過濾器用于攔截并通過責任鏈處理web請求,修改http的請求傳入數據和http響應的傳出數據,可以實現AOP處理我們的與應用無關的操作,比如安全控制等,主要包含路徑過濾器,header過濾器,參數過濾器,body過濾器,狀態過濾器,會話過濾器,重定向過濾器,重試過濾器,限流RateLimiter過濾器,熔斷器過濾器
4.1.1 Path過濾器
path過濾器主要是和請求路徑相關的一些過濾
4.1.1.1 RewritePathGatewayFilter
這個過濾器的主要作用是重寫路徑, 可以將我們的請求地址從A重寫為B再進行訪問
routes:
- id: 08consumer-eureka-feign # 當前路由策略的唯一ID,可以隨便寫
uri: lb://08CONSUMER-EUREKA-FEIGN #lb開頭代表是負載均衡,意味著需要從注冊中心獲取數據
predicates: #配置斷言, 符合下面斷言的請求會轉發到上面的url,斷言很多種條件
- Path=/abc/order/** #斷言的條件是請求的地址符合這個表達式,注意格式為Path=/abc/order/**
filters:
- RewritePath=/abc(?/?.*), $\{segment} # 將/abc/order/**重寫為/order/**,可以幫我們去掉前綴
4.1.1.2 PrefixPathGatewayFilter
這個過濾器的主要作用是給對應路由的添加一個統一的請求前綴地址
routes:
- id: 08consumer-eureka-feign # 當前路由策略的唯一ID,可以隨便寫
uri: lb://08CONSUMER-EUREKA-FEIGN #lb開頭代表是負載均衡,意味著需要從注冊中心獲取數據
predicates: #配置斷言, 符合下面斷言的請求會轉發到上面的url,斷言很多種條件
- Path=/** #斷言的條件是請求的地址符合這個表達式
filters:
- PrefixPath=/order #網關內部實際的訪問地址要在上面的path前面添加這個前綴,需要注意,拼接完之后的地址需要在對應的服務中真實存在,否則會提示404,比如我們請求網關localhost:8080/1實際訪問的是對應服務的/order/1這個地址
4.1.1.3 StripPrefixGatewayFilter
這個過濾器的主要作用是將用戶的實際請求地址跳過一部分后進行重寫轉發,這樣我們可以要求用戶多傳遞某些路徑,我們在內部裁剪后才訪問,可以不暴露真實地址
routes:
- id: 08consumer-eureka-feign # 當前路由策略的唯一ID,可以隨便寫
uri: lb://08CONSUMER-EUREKA-FEIGN #lb開頭代表是負載均衡,意味著需要從注冊中心獲取數據
predicates: #配置斷言, 符合下面斷言的請求會轉發到上面的url,斷言很多種條件
- Path=/abc/def/order/** #斷言的條件是請求的地址符合這個表達式
filters:
#作用是將真實的請求地址的前面兩層路徑去掉,比如實際訪問的地址是 /abc/def/order/1,會被修改為/order/1,想去掉幾層寫幾
- StripPrefix=2
4.1.1.4 SetPathGatewayFilter
這個過濾器的作用是將請求路徑從A轉成B,并且可以將A中的某個參數的值填寫到B地址中
routes:
- id: 08consumer-eureka-feign # 當前路由策略的唯一ID,可以隨便寫
uri: lb://08CONSUMER-EUREKA-FEIGN #lb開頭代表是負載均衡,意味著需要從注冊中心獲取數據
predicates: #配置斷言, 符合下面斷言的請求會轉發到上面的url,斷言很多種條件
- Path=/abc/def/aaa/{segment} # 請求網關的時候必須匹配當前的路徑格式, 最后的{segment}想當于 pathvariable
filters:
#將上面的請求地址轉成下面的格式, 并將對應的參數設置到這里來,參數名和參數名對應即可
- SetPath=/order/{segment}
4.1.1.5 RedirectToGatewayFilter
重定向過濾器,向客戶端返回指定的重定向地址
routes:
- id: 08consumer-eureka-feign # 當前路由策略的唯一ID,可以隨便寫
uri: lb://08CONSUMER-EUREKA-FEIGN #lb開頭代表是負載均衡,意味著需要從注冊中心獲取數據
predicates: #配置斷言, 符合下面斷言的請求會轉發到上面的url,斷言很多種條件
- Path=/abc/def/aaa/{segment} # 請求網關的時候必須匹配當前的路徑格式
filters:
- RedirectTo=302, https://www.baidu.com #設置重定向,返回狀態碼302,重定向到https://www.baidu.com
4.1.2 參數過濾器
4.1.2.1 AddRequestParameter
這個過濾器的作用是網關會向下游服務添加某個參數,這樣可以在不需要客戶端傳遞某個參數的情況下傳遞額外參數,比如當前網關的標識等
spring:
cloud:
gateway:
routes:
- id: 08consumer-eureka-feign # 當前路由策略的唯一ID,可以隨便寫
uri: lb://08CONSUMER-EUREKA-FEIGN #lb開頭代表是負載均衡,意味著需要從注冊中心獲取數據
predicates:
- Host: {segment}.myhost.org #必須是通過某個域名請求的才可以訪問
filters:
- AddRequestParameter=foo, bar-{segment} #向下游添加一個名字叫foo,值為bar-{segment}的內容的數據,這個數據可以寫死,也可以通過表達式獲取,類似于上面pathvariable,根據實際情況決定
4.1.2.2 RemoveRequestParameter
這個的作用是將客戶端傳遞的某個參數移除,不傳遞到下游服務
routes:
- id: 08consumer-eureka-feign # 當前路由策略的唯一ID,可以隨便寫
uri: lb://08CONSUMER-EUREKA-FEIGN #lb開頭代表是負載均衡,意味著需要從注冊中心獲取數據
predicates: #配置斷言, 符合下面斷言的請求會轉發到上面的url,斷言很多種條件
- Path=/test3333 # 請求網關的時候必須匹配當前的路徑格式
filters:
- RemoveRequestParameter=name #刪除客戶端傳遞的名字叫name的參數
4.1.3 狀態過濾器
4.1.3.1 SetStatusGatewayFilter
這個過濾器的主要作用是返回全局的狀態碼,不管是什么結果都返回指定的狀態碼
routes:
- id: 08consumer-eureka-feign # 當前路由策略的唯一ID,可以隨便寫
uri: lb://08CONSUMER-EUREKA-FEIGN #lb開頭代表是負載均衡,意味著需要從注冊中心獲取數據
predicates: #配置斷言, 符合下面斷言的請求會轉發到上面的url,斷言很多種條件
- Path=/** # 請求網關的時候必須匹配當前的路徑格式
filters:
#設置統一的狀態碼,不管怎么著都會返回404,注意要查看網絡請求返回的狀態碼,不要只看頁面,這里也可以寫常量的名字
- SetStatus=404
4.1.4 Header頭部過濾器
這些過濾器的操作都是和header相關的,包括添加,刪除值等
4.1.4.1 AddRequestHeaderGatewayFilter
這個過濾器是向請求頭中添加header,并傳遞到下游服務
filters:
- AddRequestHeader=X-Request-red, blue #向下游服務添加名字叫X-Request-red值為blue的請求頭,這個頭中的數據也可以向上面的過濾器一樣,來自于其他配置參數的pathvariable
4.1.4.2 AddResponseHeaderGatewayFilter
這個過濾器的主要作用是向客戶端的響應添加響應頭的
filters:
- AddResponseHeader=foo, bar-{segment} #向客戶端添加一個名字叫foo, 值叫bar-{segment}的數據,{segment}的值取決于配置的其他數據,類似于上面的的過濾器的pathvariable
4.1.4.3 RemoveRequestHeader
此過濾器的作用是將客戶端傳遞的某個請求頭刪除,不向下游服務傳遞
filters:
- RemoveRequestHeader=X-Request-Foo #移除名字叫X-Request-Foo的請求頭
4.1.4.4 RemoveResponseHeader
這個過濾器的作用是將下游服務返回給我們的某個請求頭刪除,不返回給客戶端
filters:
- RemoveResponseHeader=X-Response-Foo #從下游服務中刪除X-Response-Foo頭數據
4.1.4.5 SetRequestHeaderGatewayFilter
這個過濾器的作用是設置某個客戶端傳遞的請求頭的數據,是替換掉用戶傳遞的某個頭,而不是添加
filters:
- SetRequestHeader=X-Request-Red, Blue #將請求頭中X-Request-Red的值設置為Blue,不會添加
4.1.4.6 SetResponseHeaderGatewayFilter
這個過濾器的作用是將下游服務返回的響應頭數據替換掉
filters:
- SetResponseHeader=X-Response-Red, Blue #將下游服務返回的名字叫X-Response-Red的響應頭數據設置為Blue返回給客戶端
4.1.4.7 RequestRateLimiter
限流的過濾器,可以幫我們實現限流,使用的是居于令牌桶算法實現的限流措施,需要用到redis,當請求超過限制的流量的時候會返回HTTP 429 - Too Many Requests
4.1.4.7.1 依賴
org.springframework.boot
spring-boot-starter-data-redis-reactive
4.1.4.7.2 限流配置
此處已全局的默認過濾器為設置,默認過濾器可以參考下面
穩定速率是通過在replenishRate(補充令牌速度) 和 burstCapacity(令牌桶容量)中設置相同的值來實現的。可通過設置burstCapacity高于replenishRate來允許臨時突發流浪。在這種情況下,限流器需要在兩次突發之間留出一段時間(根據replenishRate),因為連續兩次突發將導致請求丟失 (HTTP 429 - Too Many Requests).
要限制每秒一個請求,可以將replenishRate設置為目標請求數,requestedTokens設置目標的時間秒數,burstCapacity為replenishRate * requestedTokens。如:設置replenishRate=1, requestedTokens=60 和 burstCapacity=60,就是限制每分鐘1個請求.
spring:
cloud:
gateway:
default-filters:
- name: RequestRateLimiter
args:
redis-rate-limiter.replenishRate: 1 #允許每個用戶每秒執行多少請求,而不丟棄任何請求。這是令牌桶的填充速率
redis-rate-limiter.burstCapacity: 1 #允許一秒鐘內執行的最大請求數。這是令牌桶可以保存的令牌數。將此值設置為零將阻止所有請求。
redis-rate-limiter.requestedTokens: 1 #每個請求消耗多少個令牌,默認是1
key-resolver: "#{@myKeyResolver}" #這個必須要配置,否則返回403
4.1.4.7.3 myKeyResolver
myKeyResolver 的作用是從spring bean中找到一個名字叫做myKeyResolver的對象,這個對象會返回一個數據,讓我們區分是不是來自于同一個用戶的請求
@Bean
KeyResolver myKeyResolver() {
//通過獲取用戶的ip地址來判斷是不是一個用戶,根據實際情況,比如可以通過某個頭或者token或者參數等等來區分,只要在這里自己返回即可
return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getAddress().getHostAddress());
//return exchange->Mono.just(exchange.getRequest().getQueryParams().getFirst("canshu")); //按照某個參數限流
}
4.2 默認過濾器
如果想給所有的請求設置默認的網關路由過濾器,則可以通過下面的配置進行設置
spring:
cloud:
gateway:
default-filters: #下面設置的就是默認的過濾器,可以是springcloud中支持的gatewayfilter中的任意一些
- AddResponseHeader=X-Response-Default-Red, Default-Blue
- PrefixPath=/httpbin
4.3 Body過濾器
這個過濾器的主要作用是處理請求正文和響應正文的數據,body過濾器只能通過Java代碼的方式進行配置
body過濾器
4.3.1 ModifyRequestBodyGatewayFilter
這個過濾器的作用是處理請求正文,將用戶傳遞的正文數據轉換為其他的內容,可以是數據內容發生變化,也可以是類型發生變化
方法展示
大體代碼,根據實際需求來編寫
如果客戶端傳過來的數據是空的,我們需要返回 Mono.empty()
空數據處理
@Bean
public RouteLocator routes(RouteLocatorBuilder builder) {
return builder.routes()
.route("rewrite_request_obj", r -> r.path("/user")//設置匹配的地址
.filters(f -> f
//.prefixPath("/httpbin")//設置前綴
// .redirect(302,"http://www.baidu.com")//重定向
//.addRequestHeader("dadas","dadasd")//添加請求頭
// 更多操作查看代碼api
//處理修改請求正文
//參數1 客戶端輸入的數據類型
//參數2 網關期望轉換后的目標類型
//參數3, 用戶傳遞的數據的格式
//參數4 如何轉換數據到目標類型
.modifyRequestBody(String.class, User.class, MediaType.APPLICATION_JSON_VALUE,
(exchange, s) -> {
try {
return Mono.just(objectMapper.readValue(s, User.class));
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return Mono.empty();
}))
.uri("lb://08consumer-eureka-feign"))//設置目標服務的地址,可以使用lb://
.build();
}
4.3.2 ModifyResponseBodyGatewayFilter
這個過濾器的作用是修改結果的數據, 操作和上面的請求正文的一樣,必須java編寫
只是方法由modifyRequestBody變成modifyResponseBody而已
@Bean
public RouteLocator routes(RouteLocatorBuilder builder) {
return builder.routes()
.route("rewrite_request_obj", r -> r.path("/user")//設置匹配的地址
.filters(f -> f
//.prefixPath("/httpbin")//設置前綴
// .redirect(302,"http://www.baidu.com")//重定向
//.addRequestHeader("dadas","dadasd")//添加請求頭
// 更多操作查看代碼api
//自定義處理響應正文
//參數1,下游服務給我們返回的數據格式
//參數2 我們想給用戶返回的數據格式
//參數3 我們返回的content-type
//參數4 如何將下游服務的結果轉換為我們想要的及餓哦過
.modifyResponseBody(User.class,String.class, MediaType.APPLICATION_JSON_VALUE,
(exchange, s) -> {
try {
return Mono.just(objectMapper.writeValueAsString(s));
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return Mono.empty();
}))
.uri("lb://08consumer-eureka-feign"))//設置目標服務的地址,可以使用lb://
.build();
}
4.4 全局過濾器
全局過濾器和網關過濾器一樣,但是全局過濾器不需要通過配置文件或者配置類進行設置,它作用在所有路由上面,經過GatewayFilterAdapter包裝為GatewayFilterChain責任鏈,它主要將我們的請求轉換為真實的請求地址并進行訪問,不需要經過配置,會自動在系統啟動的時候進行加載
4.4.1 ForwardRoutingFilter
轉發過濾器,當前過濾器的主要作用是將請求轉發給網關本身,而不是其他服務,只需要將路由的url設置為forward:///localendpoint格式即可
當請求進來時,ForwardRoutingFilter 會查看一個URL,該URL為 exchange 屬性 ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR 的值,如果該 url 的 scheme 是 forward(例如:forward://localendpoint),那么該Filter會使用Spirng的 DispatcherHandler 來處理這個請求。該請求的URL路徑部分,會被forward URL中的路徑覆蓋掉。而未修改過的原始URL,會被追加到 ServerWebExchangeUtils.GATEWAY_ORIGINAL_REQUEST_URL_ATTR 屬性中
spring:
application:
name: juejin-gateway
cloud:
gateway:
routes:
- id: forward_sample
uri: forward:///globalfilters #將請求轉發到自己網關內的這個地址
order: 10000
predicates:
- Path=/globalfilters
filters:
- PrefixPath=/application/gateway
當我們訪問網關的 http://127.0.0.1:8080/application/gateway/globalfilters這個地址的時候(假設網關是http://127.0.0.1:8080, ForwardRoutingFilter 判斷有 forward:// 前綴( Scheme ),過濾處理,將請求轉發給 DispatcherHandler,DispatcherHandler 匹配并轉發到當前網關實例本地接口 application/gateway/globalfilters ,需要通過 PrefixPathGatewayFilterFactory 將請求重寫路徑,以匹配本地 API ,否則 DispatcherHandler 轉發會失敗
4.4.2 LoadBalancerClientFilter
這個過濾器的主要作用是進行負載均衡的,當我們的url是lb://myservice格式的時候,會從注冊中心找地址進行訪問,當前方式是阻塞的同步方式
當請求進來時,LoadBalancerClientFilter 會查看一個URL,該URL為 exchange 的屬性 ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR 的值,如果該 url 的 scheme 是 lb,(例如:lb://myservice ),那么該Filter會使用Spring Cloud的 LoadBalancerClient 來將 myservice 解析成實際的host 和 port ,并替換掉原本 ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR 屬性的值。而原始 url 會追加到 ServerWebExchangeUtils.GATEWAY_ORIGINAL_REQUEST_URL_ATTR 屬性中。該過濾器還會查看 ServerWebExchangeUtils.GATEWAY_SCHEME_PREFIX_ATTR 屬性,如果發現該屬性的值是 lb ,也會執行相同邏輯。
注意服務找不到會提示503
4.4.3 ReactiveLoadBalancerClientFilter
和LoadBalancerClientFilter一樣的作用,只不過是非阻塞的方式,只需要在配置中通過spring.cloud.loadbalancer.ribbon.enabled=fasle來停用上面的方式即可自動開啟非同步的
4.4.4 NettyRoutingFilter
NettyRoutingFilter ,Netty 路由網關過濾器。其根據 http:// 或 https:// 前綴( Scheme )過濾處理,使用基于 Netty 實現的 HttpClient 請求后端 Http 服務。
當請求進來時,NettyRoutingFilter 會查看一個URL,該URL是 exchange 的屬性 ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR 的值,如果該 url 的 scheme 是 http 或 https ,那么該Filter會使用 Netty 的 HttpClient 向下游的服務發送代理請求。獲得的響應將放在 exchange 的 ServerWebExchangeUtils.CLIENT_RESPONSE_ATTR 屬性中,以便在后面的 Filter 里使用。(有一個實驗性的過濾器: WebClientHttpRoutingFilter 可實現相同功能,但無需Netty)
4.4.5 NettyWriteResponseFilter
NettyWriteResponseFilter 用于將代理響應寫回網關的客戶端側,所以該過濾器會在所有其他過濾器執行完成后才執行,并且執行的條件是 exchange 中 ServerWebExchangeUtils.CLIENT_RESPONSE_CONN_ATTR 屬性的值不為空,該值為 Netty 的 Connection 實例。(有一個實驗性的過濾器: WebClientWriteResponseFilter 可實現相同功能,但無需Netty)
4.4.6 RouteToRequestUrlFilter
這個過濾器是根據當前的請求地址找到匹配的路由設置,然后轉換出真實的請求url
當請求進來時,RouteToRequestUrlFilter 會從 exchange 中獲取 ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR 屬性的值,該值是一個 Route 對象。若該對象不為空的話,RouteToRequestUrlFilter 會基于請求 URL 及 Route 對象里的 URL 來創建一個新的 URL。新 URL 會被放到 exchange 的 ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR 屬性中
4.4.7 Websocket Routing Filter
該過濾器的作用與 NettyRoutingFilter 類似。當請求進來時,WebsocketRoutingFilter 會查看一個URL,該URL是 exchange 中 ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR 屬性的值,如果該 url 的 scheme 是 ws 或者 wss,那么該Filter會使用 Spring Web Socket 將 Websocket 請求轉發到下游。
另外,如果 Websocket 請求需要負載均衡的話,可為URL添加 lb 前綴以實現負載均衡,例如 lb:ws://serviceid
4.4.8 Gateway Metrics Filter
想要啟用Gateway Metrics Filter,需在項目中添加 spring-boot-starter-actuator 依賴,然后在配置文件中配置 spring.cloud.gateway.metrics.enabled 的值為true。該過濾器會添加名為 gateway.requests 的時序度量(timer metric),其中包含以下標記
4.5.1 自定義過濾器
public class MyGatewayFilterFactory extends AbstractGatewayFilterFactory<MyGatewayFilterFactory.Config> {
public MyGatewayFilterFactory() {
super(Config.class);
}
/**
*
* @param config 我們自己定義的config類的對象,在使用的時候需要傳遞進來
* @return
*/
@Override
public GatewayFilter apply(Config config) {
return (exchange, chain) -> {
//獲取到請求相關的數據,都會被封裝到builder對象中,根據實際業務來處理即可,如果需要數據可以傳遞過來
ServerHttpRequest.Builder builder = exchange.getRequest().mutate();
return chain.filter(exchange.mutate().request(builder.build()).build());
};
}
public static class Config {
//如果需要自定義的config,在這里可以定義自己需要的數據,然后傳遞過啦
}
}
4.5.2 使用自定義過濾器
@Bean
public RouteLocator routes(RouteLocatorBuilder builder) {
return builder.routes()
.route("rewrite_request_obj", r -> r.path("/user")//設置匹配的地址
.filters(f -> f
//.prefixPath("/httpbin")//設置前綴
// .redirect(302,"http://www.baidu.com")//重定向
//.addRequestHeader("dadas","dadasd")//添加請求頭
// 更多操作查看代碼api
//處理修改請求正文
//參數1 客戶端輸入的數據類型
//參數2 網關期望轉換后的目標類型
//參數3, 用戶傳遞的數據的格式
//參數4 如何轉換數據到目標類型
.modifyRequestBody(String.class, User.class, MediaType.APPLICATION_JSON_VALUE,
(exchange, s) -> {
try {
return Mono.just(objectMapper.readValue(s, User.class));
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return Mono.empty();
})
//添加過濾器,可以添加自己的定義的過濾器, 在這里可以創建并傳遞自己需要的config對象進去
.filter(new MyGatewayFilterFactory().apply(new MyGatewayFilterFactory.Config()))
//自定義處理響應正文
//參數1,下游服務給我們返回的數據格式
//參數2 我們想給用戶返回的數據格式
//參數3 我們返回的content-type
//參數4 如何將下游服務的結果轉換為我們想要的及餓哦過
.modifyResponseBody(User.class, String.class, MediaType.APPLICATION_JSON_VALUE,
(exchange, s) -> {
try {
return Mono.just(objectMapper.writeValueAsString(s));
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return Mono.empty();
}))
.uri("lb://08consumer-eureka-feign"))//設置目標服務的地址,可以使用lb://
.build();
}
自定義網關過濾器
4.6 自定義全局過濾器
全局過濾器可以通過實現GlobalFilter和Ordered接口來實現并添加@Compoment, 也可以直接通過@Bean注解聲明一個GlobalFilter返回一個匿名對象,全局過濾器作用在所有的過濾器,不需要指定路由,只要對象創建即可
4.6.1 自定義過濾器
此方式通過創建類實現接口來實現過濾器
@Component
public class MyGlobalFilter implements GlobalFilter, Ordered {
@Override
public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
System.err.println("全局過濾器執行了");
//執行下一個過濾器
return chain.filter(exchange);
}
/**
* 優先級,數字越小,優先級越高
* @return
*/
@Override
public int getOrder() {
return 0;
}
}
4.6.2 匿名對象的方式
下面的是匿名過濾器的
@Bean
@Order(-1)//指定優先級,不指定的情況下默認優先級是int的最大值,當過濾器的order一樣大的時候,會按照創建的順序來執行,這個順序只在匿名過濾器之間有效,不會和其他過濾器一起比較順序
public GlobalFilter MyFilter() {
return ((exchange, chain) -> {
System.err.println("匿名自定義的過濾器執行了了");
return chain.filter(exchange);
});
}
開班時間:2021-04-12(深圳)
開班盛況開班時間:2021-05-17(北京)
開班盛況開班時間:2021-03-22(杭州)
開班盛況開班時間:2021-04-26(北京)
開班盛況開班時間:2021-05-10(北京)
開班盛況開班時間:2021-02-22(北京)
開班盛況開班時間:2021-07-12(北京)
預約報名開班時間:2020-09-21(上海)
開班盛況開班時間:2021-07-12(北京)
預約報名開班時間:2019-07-22(北京)
開班盛況Copyright 2011-2023 北京千鋒互聯科技有限公司 .All Right 京ICP備12003911號-5 京公網安備 11010802035720號