__init__.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382
  1. #!/usr/bin/env python3
  2. # -*- coding: utf-8 -*-
  3. from fastapi import APIRouter, Request, Depends,Response,HTTPException,status,Query
  4. from fastapi.responses import StreamingResponse
  5. from fastapi.responses import JSONResponse
  6. from cachetools.keys import hashkey
  7. from sqlalchemy.orm import Session
  8. from typing import List, Optional
  9. from cachetools import LRUCache
  10. from pydantic import BaseModel
  11. from database import get_db
  12. from urllib import parse
  13. from models import *
  14. import requests
  15. import hashlib
  16. import random
  17. import string
  18. import json
  19. import time
  20. import io
  21. router = APIRouter()
  22. def GetSign(signTime,nonce,passtoken):
  23. data = signTime+passtoken+nonce+signTime
  24. return hashlib.sha256(data.encode('utf-8')).hexdigest()
  25. def GetNonce(length):
  26. characters = string.ascii_letters + string.digits
  27. # 随机选择字符集的长度个字符
  28. random_string = ''.join(random.choice(characters) for _ in range(length))
  29. return random_string
  30. def GetTime():
  31. return int(time.time()*1000)
  32. # 设置缓存大小,例如 100 个缓存项
  33. cache_size = 10000
  34. cache = LRUCache(maxsize=cache_size)
  35. # 缓存过期时间,例如 10 分钟
  36. cache.ttl = 86400 # ttl(Time to Live) 以秒为单位
  37. @router.post('/proxyHandler/{city_code:path}/{service_code:path}')
  38. @router.get('/proxyHandler/{city_code:path}/{service_code:path}')
  39. async def mine(request: Request,db: Session = Depends(get_db)):
  40. target = str(request.url) # 获取接口地址
  41. cache_key = hashkey(target)
  42. cached_response = cache.get(cache_key)
  43. if cached_response:
  44. if 'image/png' in cached_response.headers.get('Content-Type', ''):
  45. return StreamingResponse(content=io.BytesIO(cached_response.content), media_type='image/png')
  46. return cached_response
  47. # 获取接口id 判断接口是否存在
  48. service_code = request.path_params.get('service_code')
  49. service_info = db.query(OneShareApiEntity).filter(OneShareApiEntity.servercode==service_code).first()
  50. if service_info is None:
  51. return JSONResponse(status_code=410, content={
  52. 'code': 410,
  53. 'msg': f'server_code{service_code}服务不存在'
  54. })
  55. city_code = request.path_params.get('city_code')
  56. if city_code == "mm":
  57. url = 'https://19.155.242.125/GatewayMsg/http/api/proxy/invoke'
  58. elif city_code == "gd":
  59. url = 'https://19.15.75.180:8581/GatewayMsg/http/api/proxy/invoke'
  60. else:
  61. return JSONResponse(status_code=410, content={
  62. 'code': 410,
  63. 'msg': f'city_code{city_code}不存在'
  64. })
  65. # 获取请求方式
  66. method = request.method
  67. # 获取请求体
  68. body = await request.body()
  69. body = body.decode(encoding='utf-8')
  70. if len(body) > 0:
  71. body = json.loads(body)
  72. # 获取默认params 1
  73. params_default = service_info.params_default
  74. if len(params_default)>0:
  75. print(params_default)
  76. params_default = json.loads(params_default)
  77. # 获取params
  78. query_list = parse.parse_qsl(str(request.query_params))
  79. params = {}
  80. for (key, val) in query_list:
  81. params[key]=val
  82. params_default.update(params)
  83. params = params_default
  84. # 生成请求头主体
  85. signTime = str(GetTime()//1000)
  86. nonce = GetNonce(5)
  87. sign = GetSign(signTime,nonce,service_info.passtoken)
  88. # 初始请求头
  89. headers = {
  90. # 'Content-Type': 'application/json',
  91. 'x-tif-signature': sign,
  92. 'x-tif-timestamp': signTime,
  93. 'x-tif-nonce': nonce,
  94. 'x-tif-paasid': service_info.passid,
  95. 'x-tif-serviceId': service_code
  96. }
  97. # 加入默认请求头
  98. headers_default = service_info.headers_default
  99. if len(headers_default)>0:
  100. headers_default = json.loads(headers_default)
  101. headers.update(headers_default)
  102. # 判断接口类型
  103. # 1 普通接口 请求头请求体用默认,前端传输的请求体嵌入到请求体query中
  104. # 2 地图接口
  105. # 3 自定义接口
  106. if service_info.servertype == 1:
  107. query_timestamp = str(GetTime())
  108. data = {
  109. "system_id": service_info.passid,
  110. "vender_id": 'xx',
  111. "department_id": 'xx',
  112. "query_timestamp": query_timestamp,
  113. "UID": GetNonce(5),
  114. "query": body,
  115. "audit_info": {
  116. "operator_id": 'xx',
  117. "operator_name": 'xx',
  118. "query_object_id": 'xx',
  119. "query_object_id_type": 'xx',
  120. "item_id": 'xx',
  121. "item_code": 'xx',
  122. "item_sequence": 'xx',
  123. "terminal_info": 'xx',
  124. "query_timestamp": query_timestamp
  125. }
  126. }
  127. body=data
  128. else:
  129. body_default = service_info.body_default
  130. if len(body_default)>0:
  131. body_default = json.loads(body_default)
  132. body_default.update(body)
  133. # 根据请求方式请求获取数据
  134. if method == "GET":
  135. response = requests.get(url=url,params=params,headers=headers,json=body,verify=False)
  136. elif method == "POST":
  137. response = requests.post(url=url,params=params,headers=headers,json=body,verify=False)
  138. else:
  139. return JSONResponse(status_code=410, content={
  140. 'code': 410,
  141. 'msg': f'请求方式{method}不支持'
  142. })
  143. # 根据响应头数据类型返回对应数据类型
  144. content_type = response.headers.get('Content-Type', '')
  145. if 'application/json' in content_type:
  146. return JSONResponse(content=response.json(), media_type='application/json',status_code=response.status_code)
  147. elif 'application/xml' in content_type or 'text/xml' in content_type:
  148. return Response(content=response.text, media_type='application/xml',status_code=response.status_code)
  149. elif 'text/html' in content_type:
  150. return Response(content=response.text, media_type='application/html',status_code=response.status_code)
  151. elif 'image/png' in content_type:
  152. cache[cache_key] = response
  153. return StreamingResponse(content=io.BytesIO(response.content), media_type='image/png')
  154. # 可以继续添加更多的条件分支来处理其他类型
  155. else:
  156. return Response(content=response.text, media_type=content_type)
  157. class OneShareApiCreateForm(BaseModel):
  158. passid: str
  159. passtoken: str
  160. servercode: str
  161. servertype: int
  162. params_default: str = ""
  163. body_default: str = ""
  164. headers_default: str = ""
  165. servername: str
  166. @router.post("/create")
  167. async def create_one_share_api(
  168. api_data: OneShareApiCreateForm,
  169. db: Session = Depends(get_db)
  170. ):
  171. try:
  172. # 创建一个新的 OneShareApiEntity 实例
  173. new_api = OneShareApiEntity(
  174. passid=api_data.passid,
  175. passtoken=api_data.passtoken,
  176. servercode=api_data.servercode,
  177. servertype=api_data.servertype,
  178. params_default=api_data.params_default,
  179. body_default=api_data.body_default,
  180. headers_default=api_data.headers_default,
  181. servername=api_data.servername
  182. )
  183. # 添加到数据库会话并提交
  184. db.add(new_api)
  185. db.commit()
  186. db.refresh(new_api) # 刷新实例以包含新的 ID 等信息
  187. # 构建并返回响应
  188. return {
  189. "code": 200,
  190. "msg": "操作成功",
  191. "data": None
  192. }
  193. except Exception as e:
  194. # 处理异常
  195. raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e))
  196. class OneShareApiUpdateForm(BaseModel):
  197. passid: str = None
  198. passtoken: str = None
  199. servercode: str = None
  200. servertype: int = None
  201. params_default: str = None
  202. body_default: str = None
  203. headers_default: str = None
  204. servername: str = None
  205. @router.put("/update/{id}") # 或者使用 @app.patch 如果你只想更新部分字段
  206. async def update_one_share_api(
  207. id: int,
  208. api_data: OneShareApiUpdateForm,
  209. db: Session = Depends(get_db)
  210. ):
  211. try:
  212. # 从数据库中获取现有的 OneShareApiEntity 实例
  213. api = db.query(OneShareApiEntity).filter(OneShareApiEntity.id == id).first()
  214. if not api:
  215. raise HTTPException(status_code=404, detail="接口不存在")
  216. # 更新字段
  217. if api_data.passid:
  218. api.passid = api_data.passid
  219. if api_data.passtoken:
  220. api.passtoken = api_data.passtoken
  221. if api_data.servercode:
  222. api.servercode = api_data.servercode
  223. if api_data.servertype:
  224. api.servertype = api_data.servertype
  225. if api_data.params_default:
  226. api.params_default = api_data.params_default
  227. if api_data.body_default:
  228. api.body_default = api_data.body_default
  229. if api_data.headers_default:
  230. api.headers_default = api_data.headers_default
  231. if api_data.servername:
  232. api.servername = api_data.servername
  233. # 更新时间
  234. api.update_time = datetime.now()
  235. # 提交更改
  236. db.commit()
  237. # 构建并返回响应
  238. return {
  239. "code": 200,
  240. "msg": "操作成功",
  241. "data": None
  242. }
  243. except Exception as e:
  244. # 处理异常
  245. raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e))
  246. @router.delete("/delete/{id}") # 使用 ID 来标识要删除的接口
  247. async def delete_one_share_api(
  248. id: int,
  249. db: Session = Depends(get_db)
  250. ):
  251. # try:
  252. # 从数据库中获取要删除的 OneShareApiEntity 实例
  253. api = db.query(OneShareApiEntity).filter(OneShareApiEntity.id == id).first()
  254. if api is None:
  255. raise HTTPException(status_code=404, detail="接口不存在")
  256. # 删除实例
  257. db.delete(api)
  258. db.commit()
  259. # 构建并返回响应
  260. return {
  261. "code": 200,
  262. "msg": "操作成功",
  263. "data": None
  264. }
  265. # except Exception as e:
  266. # # 处理异常
  267. # print(e)
  268. # raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e))
  269. class OneShareApiOut(BaseModel):
  270. id: int
  271. passid: str
  272. passtoken: str
  273. servercode: str
  274. servertype: int
  275. params_default: str
  276. body_default: str
  277. headers_default: str
  278. servername: str
  279. create_time: str
  280. update_time: str
  281. # 定义查询接口的路由
  282. @router.get("/list")
  283. async def get_one_share_apis(
  284. page: int = Query(1, gt=0),
  285. page_size: int = Query(10, gt=0),
  286. servername: Optional[str] = Query(None),
  287. servertype:int = Query(None),
  288. servercode: Optional[str] = Query(None),
  289. db: Session = Depends(get_db)
  290. ):
  291. try:
  292. # 构建查询
  293. query = db.query(OneShareApiEntity)
  294. # 应用查询参数
  295. if servername:
  296. query = query.filter(OneShareApiEntity.servername.contains(servername))
  297. if servercode:
  298. query = query.filter(OneShareApiEntity.servercode.contains(servercode))
  299. if servertype:
  300. query = query.filter(OneShareApiEntity.servertype==servertype)
  301. # 获取总记录数
  302. total_count = query.count()
  303. # 执行分页查询
  304. items = query.offset((page - 1) * page_size).limit(page_size).all()
  305. # 将查询结果转换为 Pydantic 模型列表
  306. apis_out = [
  307. OneShareApiOut(
  308. id=item.id,
  309. passid=item.passid,
  310. passtoken=item.passtoken,
  311. servercode=item.servercode,
  312. servertype=item.servertype,
  313. params_default=item.params_default,
  314. body_default=item.body_default,
  315. headers_default=item.headers_default,
  316. servername=item.servername,
  317. create_time=item.create_time.strftime('%Y-%m-%d %H:%M:%S'),
  318. update_time=item.update_time.strftime('%Y-%m-%d %H:%M:%S')
  319. ) for item in items
  320. ]
  321. # 构建并返回响应
  322. return {
  323. "code": 200,
  324. "msg": "查询成功",
  325. "data": {
  326. "total": total_count,
  327. "list": apis_out
  328. }
  329. }
  330. except Exception as e:
  331. # 处理异常
  332. raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e))