@@ -45,22 +45,22 @@ def of_api_url(self, api_path, domain):
4545
4646 def get_jm_image (self , img_url ) -> JmImageResp :
4747
48- def judge (resp ):
48+ def callback (resp ):
4949 """
5050 使用此方法包装 self.get,使得图片数据为空时,判定为请求失败时,走重试逻辑
5151 """
5252 resp = JmImageResp (resp )
5353 resp .require_success ()
5454 return resp
5555
56- return self .get (img_url , judge = judge , headers = JmModuleConfig .new_html_headers ())
56+ return self .get (img_url , callback = callback , headers = JmModuleConfig .new_html_headers ())
5757
5858 def request_with_retry (self ,
5959 request ,
6060 url ,
6161 domain_index = 0 ,
6262 retry_count = 0 ,
63- judge = lambda resp : resp ,
63+ callback = None ,
6464 ** kwargs ,
6565 ):
6666 """
@@ -74,7 +74,7 @@ def request_with_retry(self,
7474 :param url: 图片url / path (/album/xxx)
7575 :param domain_index: 域名下标
7676 :param retry_count: 重试次数
77- :param judge: 判定响应是否成功
77+ :param callback: 回调,可以接收resp返回新的resp,也可以抛出异常强制重试
7878 :param kwargs: 请求方法的kwargs
7979 """
8080 if domain_index >= len (self .domain_list ):
@@ -104,19 +104,32 @@ def request_with_retry(self,
104104
105105 try :
106106 resp = request (url , ** kwargs )
107- return judge (resp )
108- except KeyboardInterrupt as e :
109- raise e
107+
108+ # 回调,可以接收resp返回新的resp,也可以抛出异常强制重试
109+ if callback is not None :
110+ resp = callback (resp )
111+
112+ # 依然是回调,在最后返回之前,还可以判断resp是否重试
113+ resp = self .raise_if_resp_should_retry (resp )
114+
115+ return resp
110116 except Exception as e :
111117 if self .retry_times == 0 :
112118 raise e
113119
114120 self .before_retry (e , kwargs , retry_count , url )
115121
116122 if retry_count < self .retry_times :
117- return self .request_with_retry (request , url , domain_index , retry_count + 1 , judge , ** kwargs )
123+ return self .request_with_retry (request , url , domain_index , retry_count + 1 , callback , ** kwargs )
118124 else :
119- return self .request_with_retry (request , url , domain_index + 1 , 0 , judge , ** kwargs )
125+ return self .request_with_retry (request , url , domain_index + 1 , 0 , callback , ** kwargs )
126+
127+ # noinspection PyMethodMayBeStatic
128+ def raise_if_resp_should_retry (self , resp ):
129+ """
130+ 依然是回调,在最后返回之前,还可以判断resp是否重试
131+ """
132+ return resp
120133
121134 def update_request_with_specify_domain (self , kwargs : dict , domain : str ):
122135 """
@@ -269,12 +282,12 @@ def get_photo_detail(self,
269282
270283 return photo
271284
272- def fetch_detail_entity (self , apid , prefix ):
285+ def fetch_detail_entity (self , jmid , prefix ):
273286 # 参数校验
274- apid = JmcomicText .parse_to_jm_id (apid )
287+ jmid = JmcomicText .parse_to_jm_id (jmid )
275288
276289 # 请求
277- resp = self .get_jm_html (f"/{ prefix } /{ apid } " )
290+ resp = self .get_jm_html (f"/{ prefix } /{ jmid } " )
278291
279292 # 用 JmcomicText 解析 html,返回实体类
280293 if prefix == 'album' :
@@ -474,10 +487,10 @@ def album_comment(self,
474487 return ret
475488
476489 @classmethod
477- def require_resp_success_else_raise (cls , resp , orig_req_url : str ):
490+ def require_resp_success_else_raise (cls , resp , url : str ):
478491 """
479492 :param resp: 响应对象
480- :param orig_req_url : /photo/12412312
493+ :param url : /photo/12412312
481494 """
482495 resp_url : str = resp .url
483496
@@ -490,11 +503,11 @@ def require_resp_success_else_raise(cls, resp, orig_req_url: str):
490503
491504 # 3. 检查错误类型
492505 def match_case (error_path ):
493- return resp_url .endswith (error_path ) and not orig_req_url .endswith (error_path )
506+ return resp_url .endswith (error_path ) and not url .endswith (error_path )
494507
495508 # 3.1 album_missing
496509 if match_case ('/error/album_missing' ):
497- ExceptionTool .raise_missing (resp , orig_req_url )
510+ ExceptionTool .raise_missing (resp , JmcomicText . parse_to_jm_id ( url ) )
498511
499512 # 3.2 user_missing
500513 if match_case ('/error/user_missing' ):
@@ -639,17 +652,17 @@ def get_scramble_id(self, photo_id, album_id=None):
639652
640653 return scramble_id
641654
642- def fetch_detail_entity (self , apid , clazz ):
655+ def fetch_detail_entity (self , jmid , clazz ):
643656 """
644657 请求实体类
645658 """
646- apid = JmcomicText .parse_to_jm_id (apid )
659+ jmid = JmcomicText .parse_to_jm_id (jmid )
647660 url = self .API_ALBUM if issubclass (clazz , JmAlbumDetail ) else self .API_CHAPTER
648- resp = self .req_api (
661+ resp = self .req_api (self . append_params_to_url (
649662 url ,
650- params = {
651- 'id' : apid ,
652- },
663+ {
664+ 'id' : jmid
665+ })
653666 )
654667
655668 return JmApiAdaptTool .parse_entity (resp .res_data , clazz )
@@ -886,18 +899,57 @@ def decide_headers_and_ts(self, kwargs, url):
886899 return ts
887900
888901 @classmethod
889- def require_resp_success (cls , resp : JmApiResp , orig_req_url : str ):
902+ def require_resp_success (cls , resp : JmApiResp , url : Optional [str ] = None ):
903+ """
904+
905+ :param resp: 响应对象
906+ :param url: 请求路径,例如 /setting
907+ """
890908 resp .require_success ()
891909
892910 # 1. 检查是否 album_missing
893911 # json: {'code': 200, 'data': []}
894912 data = resp .model ().data
895913 if isinstance (data , list ) and len (data ) == 0 :
896- ExceptionTool .raise_missing (resp , orig_req_url )
914+ ExceptionTool .raise_missing (resp , JmcomicText . parse_to_jm_id ( url ) )
897915
898916 # 2. 是否是特殊的内容
899917 # 暂无
900918
919+ def raise_if_resp_should_retry (self , resp ):
920+ """
921+ 该方法会判断resp返回值是否是json格式,
922+ 如果不是,大概率是禁漫内部异常,需要进行重试
923+
924+ 由于完整的json格式校验会有性能开销,所以只做简单的检查,
925+ 只校验第一个有效字符是不是 '{',如果不是,就认为异常数据,需要重试
926+
927+ :param resp: 响应对象
928+ :return: resp
929+ """
930+ if isinstance (resp , JmResp ):
931+ # 不对包装过的resp对象做校验,包装者自行校验
932+ # 例如图片请求
933+ return resp
934+
935+ url = resp .request .url
936+
937+ if self .API_SCRAMBLE in url :
938+ # /chapter_view_template 这个接口不是返回json数据,不做检查
939+ return resp
940+
941+ text = resp .text
942+ for char in text :
943+ if char not in (' ' , '\n ' , '\t ' ):
944+ # 找到第一个有效字符
945+ ExceptionTool .require_true (
946+ char == '{' ,
947+ f'请求不是json格式,强制重试!响应文本: [{ resp .text } ]'
948+ )
949+ return resp
950+
951+ ExceptionTool .raises_resp (f'响应无数据!request_url=[{ url } ]' , resp )
952+
901953 def after_init (self ):
902954 # 保证拥有cookies,因为移动端要求必须携带cookies,否则会直接跳转同一本子【禁漫娘】
903955 if JmModuleConfig .flag_api_client_require_cookies :
0 commit comments