国产片侵犯亲女视频播放_亚洲精品二区_在线免费国产视频_欧美精品一区二区三区在线_少妇久久久_在线观看av不卡

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Java教程 - Spring Cloud學習教程之Zuul統一異常處理與回退

Spring Cloud學習教程之Zuul統一異常處理與回退

2021-04-23 11:41洛陽融科聶晨 Java教程

Spring Cloud Zuul對異常的處理整體來說還是比較方便的,流程也比較清晰,下面這篇文章主要給大家介紹了關于Spring Cloud學習教程之Zuul統一異常處理與回退的相關資料,文中通過示例代碼介紹的非常詳細,需要的朋友可以參考借鑒,

前言

zuul 是netflix 提供的一個開源組件,致力于在云平臺上提供動態路由,監控,彈性,安全等邊緣服務的框架。也有很多公司使用它來作為網關的重要組成部分,碰巧今年公司的架構組決定自研一個網關產品,集動態路由,動態權限,限流配額等功能為一體,為其他部門的項目提供統一的外網調用管理,最終形成產品(這方面阿里其實已經有成熟的網關產品了,但是不太適用于個性化的配置,也沒有集成權限和限流降級)。

本文主要給大家介紹了關于spring cloud zuul統一異常處理與回退的相關內容,分享出來供大家參考學習,下面話不多說了,來一起看看詳細的介紹吧。

一、filter中統一異常處理

  其實在springcloud的edgware sr2版本中對于zuulfilter中的錯誤有統一的處理,但是在實際開發當中對于錯誤的響應方式,我想每個團隊都有自己的處理規范。那么如何做到自定義的異常處理呢?

我們可以先參考一下springcloud提供的senderrorfilter:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
/*
 * copyright 2013-2015 the original author or authors.
 *
 * licensed under the apache license, version 2.0 (the "license");
 * you may not use this file except in compliance with the license.
 * you may obtain a copy of the license at
 *
 *  http://www.apache.org/licenses/license-2.0
 *
 * unless required by applicable law or agreed to in writing, software
 * distributed under the license is distributed on an "as is" basis,
 * without warranties or conditions of any kind, either express or implied.
 * see the license for the specific language governing permissions and
 * limitations under the license.
 */
 
package org.springframework.cloud.netflix.zuul.filters.post;
 
import javax.servlet.requestdispatcher;
import javax.servlet.http.httpservletrequest;
import javax.servlet.http.httpservletresponse;
 
import org.apache.commons.logging.log;
import org.apache.commons.logging.logfactory;
import org.springframework.beans.factory.annotation.value;
import org.springframework.cloud.netflix.zuul.util.zuulruntimeexception;
import org.springframework.util.reflectionutils;
import org.springframework.util.stringutils;
 
import com.netflix.zuul.zuulfilter;
import com.netflix.zuul.context.requestcontext;
import com.netflix.zuul.exception.zuulexception;
 
import static org.springframework.cloud.netflix.zuul.filters.support.filterconstants.error_type;
import static org.springframework.cloud.netflix.zuul.filters.support.filterconstants.send_error_filter_order;
 
/**
 * error {@link zuulfilter} that forwards to /error (by default) if {@link requestcontext#getthrowable()} is not null.
 *
 * @author spencer gibb
 */
//todo: move to error package in edgware
public class senderrorfilter extends zuulfilter {
 
 private static final log log = logfactory.getlog(senderrorfilter.class);
 protected static final string send_error_filter_ran = "senderrorfilter.ran";
 
 @value("${error.path:/error}")
 private string errorpath;
 
 @override
 public string filtertype() {
  return error_type;
 }
 
 @override
 public int filterorder() {
  return send_error_filter_order;
 }
 
 @override
 public boolean shouldfilter() {
  requestcontext ctx = requestcontext.getcurrentcontext();
  // only forward to errorpath if it hasn't been forwarded to already
  return ctx.getthrowable() != null
    && !ctx.getboolean(send_error_filter_ran, false);
 }
 
 @override
 public object run() {
  try {
   requestcontext ctx = requestcontext.getcurrentcontext();
   zuulexception exception = findzuulexception(ctx.getthrowable());
   httpservletrequest request = ctx.getrequest();
 
   request.setattribute("javax.servlet.error.status_code", exception.nstatuscode);
 
   log.warn("error during filtering", exception);
   request.setattribute("javax.servlet.error.exception", exception);
 
   if (stringutils.hastext(exception.errorcause)) {
    request.setattribute("javax.servlet.error.message", exception.errorcause);
   }
 
   requestdispatcher dispatcher = request.getrequestdispatcher(
     this.errorpath);
   if (dispatcher != null) {
    ctx.set(send_error_filter_ran, true);
    if (!ctx.getresponse().iscommitted()) {
     ctx.setresponsestatuscode(exception.nstatuscode);
     dispatcher.forward(request, ctx.getresponse());
    }
   }
  }
  catch (exception ex) {
   reflectionutils.rethrowruntimeexception(ex);
  }
  return null;
 }
 
 zuulexception findzuulexception(throwable throwable) {
  if (throwable.getcause() instanceof zuulruntimeexception) {
   // this was a failure initiated by one of the local filters
   return (zuulexception) throwable.getcause().getcause();
  }
 
  if (throwable.getcause() instanceof zuulexception) {
   // wrapped zuul exception
   return (zuulexception) throwable.getcause();
  }
 
  if (throwable instanceof zuulexception) {
   // exception thrown by zuul lifecycle
   return (zuulexception) throwable;
  }
 
  // fallback, should never get here
  return new zuulexception(throwable, httpservletresponse.sc_internal_server_error, null);
 }
 
 public void seterrorpath(string errorpath) {
  this.errorpath = errorpath;
 }
}

在這里我們可以找到幾個關鍵點:

  1)在上述代碼中,我們可以發現filter已經將相關的錯誤信息放到request當中了:

    request.setattribute("javax.servlet.error.status_code", exception.nstatuscode);

    request.setattribute("javax.servlet.error.exception", exception);

    request.setattribute("javax.servlet.error.message", exception.errorcause);

  2)錯誤處理完畢后,會轉發到 xxx/error的地址來處理 

  那么我們可以來做個試驗,我們在gateway-service項目模塊里,創建一個會拋出異常的filter:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package com.hzgj.lyrk.springcloud.gateway.server.filter;
import com.netflix.zuul.zuulfilter;
import lombok.extern.slf4j.slf4j;
import org.springframework.stereotype.component;
@component
@slf4j
public class myzuulfilter extends zuulfilter {
 @override
 public string filtertype() {
  return "post";
 }
 
 @override
 public int filterorder() {
  return 9;
 }
 
 @override
 public boolean shouldfilter() {
  return true;
 }
 
 @override
 public object run() {
  log.info("run error test ...");
  throw new runtimeexception();
  // return null;
 }
}

  緊接著我們定義一個控制器,來做錯誤處理:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
package com.hzgj.lyrk.springcloud.gateway.server.filter;
import org.springframework.http.httpstatus;
import org.springframework.http.responseentity;
import org.springframework.web.bind.annotation.getmapping;
import org.springframework.web.bind.annotation.restcontroller;
 
import javax.servlet.http.httpservletrequest;
 
@restcontroller
public class errorhandler {
 
 @getmapping(value = "/error")
 public responseentity<errorbean> error(httpservletrequest request) {
  string message = request.getattribute("javax.servlet.error.message").tostring();
  errorbean errorbean = new errorbean();
  errorbean.setmessage(message);
  errorbean.setreason("程序出錯");
  return new responseentity<>(errorbean, httpstatus.bad_gateway);
 }
 
 private static class errorbean {
  private string message;
 
  private string reason;
 
  public string getmessage() {
   return message;
  }
 
  public void setmessage(string message) {
   this.message = message;
  }
 
  public string getreason() {
   return reason;
  }
 
  public void setreason(string reason) {
   this.reason = reason;
  }
 }
}

  啟動項目后,我們通過網關訪問一下試試:

Spring Cloud學習教程之Zuul統一異常處理與回退

二、關于zuul回退的問題

1、關于zuul的超時問題:

  這個問題網上有很多解決方案,但是我還要貼一下源代碼,請關注這個類 abstractribboncommand,在這個類里集成了hystrix與ribbon。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
/*
 * copyright 2013-2016 the original author or authors.
 *
 * licensed under the apache license, version 2.0 (the "license");
 * you may not use this file except in compliance with the license.
 * you may obtain a copy of the license at
 *
 *  http://www.apache.org/licenses/license-2.0
 *
 * unless required by applicable law or agreed to in writing, software
 * distributed under the license is distributed on an "as is" basis,
 * without warranties or conditions of any kind, either express or implied.
 * see the license for the specific language governing permissions and
 * limitations under the license.
 *
 */
 
package org.springframework.cloud.netflix.zuul.filters.route.support;
 
import org.apache.commons.logging.log;
import org.apache.commons.logging.logfactory;
import org.springframework.cloud.netflix.ribbon.ribbonclientconfiguration;
import org.springframework.cloud.netflix.ribbon.ribbonhttpresponse;
import org.springframework.cloud.netflix.ribbon.support.abstractloadbalancingclient;
import org.springframework.cloud.netflix.ribbon.support.contextawarerequest;
import org.springframework.cloud.netflix.zuul.filters.zuulproperties;
import org.springframework.cloud.netflix.zuul.filters.route.ribboncommand;
import org.springframework.cloud.netflix.zuul.filters.route.ribboncommandcontext;
import org.springframework.cloud.netflix.zuul.filters.route.zuulfallbackprovider;
import org.springframework.cloud.netflix.zuul.filters.route.fallbackprovider;
import org.springframework.http.client.clienthttpresponse;
import com.netflix.client.abstractloadbalancerawareclient;
import com.netflix.client.clientrequest;
import com.netflix.client.config.defaultclientconfigimpl;
import com.netflix.client.config.iclientconfig;
import com.netflix.client.config.iclientconfigkey;
import com.netflix.client.http.httpresponse;
import com.netflix.config.dynamicintproperty;
import com.netflix.config.dynamicpropertyfactory;
import com.netflix.hystrix.hystrixcommand;
import com.netflix.hystrix.hystrixcommandgroupkey;
import com.netflix.hystrix.hystrixcommandkey;
import com.netflix.hystrix.hystrixcommandproperties;
import com.netflix.hystrix.hystrixcommandproperties.executionisolationstrategy;
import com.netflix.hystrix.hystrixthreadpoolkey;
import com.netflix.zuul.constants.zuulconstants;
import com.netflix.zuul.context.requestcontext;
 
/**
 * @author spencer gibb
 */
public abstract class abstractribboncommand<lbc extends abstractloadbalancerawareclient<rq, rs>, rq extends clientrequest, rs extends httpresponse>
  extends hystrixcommand<clienthttpresponse> implements ribboncommand {
 
 private static final log logger = logfactory.getlog(abstractribboncommand.class);
 protected final lbc client;
 protected ribboncommandcontext context;
 protected zuulfallbackprovider zuulfallbackprovider;
 protected iclientconfig config;
 
 public abstractribboncommand(lbc client, ribboncommandcontext context,
   zuulproperties zuulproperties) {
  this("default", client, context, zuulproperties);
 }
 
 public abstractribboncommand(string commandkey, lbc client,
   ribboncommandcontext context, zuulproperties zuulproperties) {
  this(commandkey, client, context, zuulproperties, null);
 }
 
 public abstractribboncommand(string commandkey, lbc client,
         ribboncommandcontext context, zuulproperties zuulproperties,
         zuulfallbackprovider fallbackprovider) {
  this(commandkey, client, context, zuulproperties, fallbackprovider, null);
 }
 
 public abstractribboncommand(string commandkey, lbc client,
         ribboncommandcontext context, zuulproperties zuulproperties,
         zuulfallbackprovider fallbackprovider, iclientconfig config) {
  this(getsetter(commandkey, zuulproperties, config), client, context, fallbackprovider, config);
 }
 
 protected abstractribboncommand(setter setter, lbc client,
         ribboncommandcontext context,
         zuulfallbackprovider fallbackprovider, iclientconfig config) {
  super(setter);
  this.client = client;
  this.context = context;
  this.zuulfallbackprovider = fallbackprovider;
  this.config = config;
 }
 
 protected static hystrixcommandproperties.setter createsetter(iclientconfig config, string commandkey, zuulproperties zuulproperties) {
  int hystrixtimeout = gethystrixtimeout(config, commandkey);
  return hystrixcommandproperties.setter().withexecutionisolationstrategy(
    zuulproperties.getribbonisolationstrategy()).withexecutiontimeoutinmilliseconds(hystrixtimeout);
 }
 
 protected static int gethystrixtimeout(iclientconfig config, string commandkey) {
  int ribbontimeout = getribbontimeout(config, commandkey);
  dynamicpropertyfactory dynamicpropertyfactory = dynamicpropertyfactory.getinstance();
  int defaulthystrixtimeout = dynamicpropertyfactory.getintproperty("hystrix.command.default.execution.isolation.thread.timeoutinmilliseconds",
   0).get();
  int commandhystrixtimeout = dynamicpropertyfactory.getintproperty("hystrix.command." + commandkey + ".execution.isolation.thread.timeoutinmilliseconds",
   0).get();
  int hystrixtimeout;
  if(commandhystrixtimeout > 0) {
   hystrixtimeout = commandhystrixtimeout;
  }
  else if(defaulthystrixtimeout > 0) {
   hystrixtimeout = defaulthystrixtimeout;
  } else {
   hystrixtimeout = ribbontimeout;
  }
  if(hystrixtimeout < ribbontimeout) {
   logger.warn("the hystrix timeout of " + hystrixtimeout + "ms for the command " + commandkey +
    " is set lower than the combination of the ribbon read and connect timeout, " + ribbontimeout + "ms.");
  }
  return hystrixtimeout;
 }
 
 protected static int getribbontimeout(iclientconfig config, string commandkey) {
  int ribbontimeout;
  if (config == null) {
   ribbontimeout = ribbonclientconfiguration.default_read_timeout + ribbonclientconfiguration.default_connect_timeout;
  } else {
   int ribbonreadtimeout = gettimeout(config, commandkey, "readtimeout",
    iclientconfigkey.keys.readtimeout, ribbonclientconfiguration.default_read_timeout);
   int ribbonconnecttimeout = gettimeout(config, commandkey, "connecttimeout",
    iclientconfigkey.keys.connecttimeout, ribbonclientconfiguration.default_connect_timeout);
   int maxautoretries = gettimeout(config, commandkey, "maxautoretries",
    iclientconfigkey.keys.maxautoretries, defaultclientconfigimpl.default_max_auto_retries);
   int maxautoretriesnextserver = gettimeout(config, commandkey, "maxautoretriesnextserver",
    iclientconfigkey.keys.maxautoretriesnextserver, defaultclientconfigimpl.default_max_auto_retries_next_server);
   ribbontimeout = (ribbonreadtimeout + ribbonconnecttimeout) * (maxautoretries + 1) * (maxautoretriesnextserver + 1);
  }
  return ribbontimeout;
 }
 
 private static int gettimeout(iclientconfig config, string commandkey, string property, iclientconfigkey<integer> configkey, int defaultvalue) {
  dynamicpropertyfactory dynamicpropertyfactory = dynamicpropertyfactory.getinstance();
  return dynamicpropertyfactory.getintproperty(commandkey + "." + config.getnamespace() + "." + property, config.get(configkey, defaultvalue)).get();
 }
 
 @deprecated
 //todo remove in 2.0.x
 protected static setter getsetter(final string commandkey, zuulproperties zuulproperties) {
  return getsetter(commandkey, zuulproperties, null);
 }
 
 protected static setter getsetter(final string commandkey,
   zuulproperties zuulproperties, iclientconfig config) {
 
  // @formatter:off
  setter commandsetter = setter.withgroupkey(hystrixcommandgroupkey.factory.askey("ribboncommand"))
        .andcommandkey(hystrixcommandkey.factory.askey(commandkey));
  final hystrixcommandproperties.setter setter = createsetter(config, commandkey, zuulproperties);
  if (zuulproperties.getribbonisolationstrategy() == executionisolationstrategy.semaphore){
   final string name = zuulconstants.zuul_eureka + commandkey + ".semaphore.maxsemaphores";
   // we want to default to semaphore-isolation since this wraps
   // 2 others commands that are already thread isolated
   final dynamicintproperty value = dynamicpropertyfactory.getinstance()
     .getintproperty(name, zuulproperties.getsemaphore().getmaxsemaphores());
   setter.withexecutionisolationsemaphoremaxconcurrentrequests(value.get());
  } else if (zuulproperties.getthreadpool().isuseseparatethreadpools()) {
   final string threadpoolkey = zuulproperties.getthreadpool().getthreadpoolkeyprefix() + commandkey;
   commandsetter.andthreadpoolkey(hystrixthreadpoolkey.factory.askey(threadpoolkey));
  }
  
  return commandsetter.andcommandpropertiesdefaults(setter);
  // @formatter:on
 }
 
 @override
 protected clienthttpresponse run() throws exception {
  final requestcontext context = requestcontext.getcurrentcontext();
 
  rq request = createrequest();
  rs response;
  
  boolean retryableclient = this.client instanceof abstractloadbalancingclient
    && ((abstractloadbalancingclient)this.client).isclientretryable((contextawarerequest)request);
  
  if (retryableclient) {
   response = this.client.execute(request, config);
  } else {
   response = this.client.executewithloadbalancer(request, config);
  }
  context.set("ribbonresponse", response);
 
  // explicitly close the httpresponse if the hystrix command timed out to
  // release the underlying http connection held by the response.
  //
  if (this.isresponsetimedout()) {
   if (response != null) {
    response.close();
   }
  }
 
  return new ribbonhttpresponse(response);
 }
 
 @override
 protected clienthttpresponse getfallback() {
  if(zuulfallbackprovider != null) {
   return getfallbackresponse();
  }
  return super.getfallback();
 }
 
 protected clienthttpresponse getfallbackresponse() {
  if (zuulfallbackprovider instanceof fallbackprovider) {
   throwable cause = getfailedexecutionexception();
   cause = cause == null ? getexecutionexception() : cause;
   if (cause == null) {
    zuulfallbackprovider.fallbackresponse();
   } else {
    return ((fallbackprovider) zuulfallbackprovider).fallbackresponse(cause);
   }
  }
  return zuulfallbackprovider.fallbackresponse();
 }
 
 public lbc getclient() {
  return client;
 }
 
 public ribboncommandcontext getcontext() {
  return context;
 }
 
 protected abstract rq createrequest() throws exception;
}

  請注意:getribbontimeout方法與gethystrixtimeout方法,其中這兩個方法 commandkey的值為路由的名稱,比如說我們訪問:http://localhost:8088/order-server/xxx來訪問order-server服務, 那么commandkey 就為order-server

  根據源代碼,我們先設置gateway-server的超時參數:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#全局的ribbon設置
ribbon:
 connecttimeout: 3000
 readtimeout: 3000
hystrix:
 command:
 default:
  execution:
  isolation:
   thread:
   timeoutinmilliseconds: 3000
zuul:
 host:
 connecttimeoutmillis: 10000

  當然也可以單獨為order-server設置ribbon的超時參數:order-server.ribbon.xxxx=xxx , 為了演示zuul中的回退效果,我在這里把hystrix超時時間設置短一點。當然最好不要將hystrix默認的超時時間設置的比ribbon的超時時間短,源碼里遇到此情況已經給與我們警告了。

  那么我們在order-server下添加如下方法:

?
1
2
3
4
5
@getmapping("/sleep/{sleeptime}")
 public string sleep(@pathvariable long sleeptime) throws interruptedexception {
  timeunit.seconds.sleep(sleeptime);
  return "success";
 }

2、zuul的回退方法

我們可以實現zuulfallbackprovider接口,實現代碼:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
package com.hzgj.lyrk.springcloud.gateway.server.filter;
import com.google.common.collect.immutablemap;
import com.google.gson.gsonbuilder;
import org.springframework.cloud.netflix.zuul.filters.route.zuulfallbackprovider;
import org.springframework.http.httpheaders;
import org.springframework.http.httpstatus;
import org.springframework.http.mediatype;
import org.springframework.http.client.clienthttpresponse;
import org.springframework.stereotype.component;
import java.io.bytearrayinputstream;
import java.io.ioexception;
import java.io.inputstream;
import java.time.localdatetime;
import java.time.localtime;
@component
public class fallbackhandler implements zuulfallbackprovider {
 
 @override
 public string getroute() {
  //代表所有的路由都適配該設置
  return "*";
 }
 
 @override
 public clienthttpresponse fallbackresponse() {
  return new clienthttpresponse() {
   @override
   public httpstatus getstatuscode() throws ioexception {
    return httpstatus.ok;
   }
 
   @override
   public int getrawstatuscode() throws ioexception {
    return 200;
   }
 
   @override
   public string getstatustext() throws ioexception {
    return "ok";
   }
 
   @override
   public void close() {
 
   }
 
   @override
   public inputstream getbody() throws ioexception {
    string result = new gsonbuilder().create().tojson(immutablemap.of("errorcode", 500, "content", "請求失敗", "time", localdatetime.now()));
    return new bytearrayinputstream(result.getbytes());
   }
 
   @override
   public httpheaders getheaders() {
    httpheaders headers = new httpheaders();
    headers.setcontenttype(mediatype.application_json);
    return headers;
   }
  };
 }
}

此時我們訪問:http://localhost:8088/order-server/sleep/6 得到如下結果:

Spring Cloud學習教程之Zuul統一異常處理與回退

當我們訪問:http://localhost:8088/order-server/sleep/1 就得到如下結果:

Spring Cloud學習教程之Zuul統一異常處理與回退

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對服務器之家的支持。

原文鏈接:http://www.cnblogs.com/niechen/p/8856551.html

延伸 · 閱讀

精彩推薦
Weibo Article 1 Weibo Article 2 Weibo Article 3 Weibo Article 4 Weibo Article 5 Weibo Article 6 Weibo Article 7 Weibo Article 8 Weibo Article 9 Weibo Article 10 Weibo Article 11 Weibo Article 12 Weibo Article 13 Weibo Article 14 Weibo Article 15 Weibo Article 16 Weibo Article 17 Weibo Article 18 Weibo Article 19 Weibo Article 20 Weibo Article 21 Weibo Article 22 Weibo Article 23 Weibo Article 24 Weibo Article 25 Weibo Article 26 Weibo Article 27 Weibo Article 28 Weibo Article 29 Weibo Article 30 Weibo Article 31 Weibo Article 32 Weibo Article 33 Weibo Article 34 Weibo Article 35 Weibo Article 36 Weibo Article 37 Weibo Article 38 Weibo Article 39 Weibo Article 40
主站蜘蛛池模板: 一级黄色小视频 | 日韩中文字幕在线观看 | 日韩精品三区 | 四虎中文字幕 | 亚洲国产中文字幕在线 | 亚洲精品a | 在线视频一区二区 | 欧洲精品视频在线观看 | av在线免费观看网址 | 日本一区二区三区免费观看 | 一级网站在线观看 | 一级片在线播放 | 欧美片网站免费 | 亚洲国产免费 | 日韩av在线中文字幕 | 99精品免费视频 | 一区二区视频在线观看 | 99视频在线 | 国产一区二区三区免费在线观看 | 日韩a | 欧美一区二区三区久久久久久桃花 | 婷婷激情综合 | 久久中文字幕精品 | 午夜成人在线视频 | 日韩在线视频免费 | av在线精品 | 一区二区三区在线免费观看 | 黄网免费看 | 日韩精品专区 | 91在线看 | 亚洲精品一区二区三区不 | 转生成为史莱姆这档事第四季在线观看 | 在线欧美日韩 | 日韩激情一区二区三区 | 欧美在线免费 | 亚洲电影一区二区三区 | 国产黄色片免费观看 | 亚洲国产成人久久 | 中文字幕亚洲一区 | 久久精品国产一区二区三区不卡 | 久久性 |