mirror of
https://git.oceanpay.cc/danial/kami_jd_ck.git
synced 2025-12-18 21:10:18 +00:00
- 修改 .drone.yml 中的 Docker Compose 命令,使用 jd_bind_card_server 代替 bind_card - 更新 .gitignore 文件,使用通配符路径以更全面地忽略文件和目录 - 在 babel_channel/app.py 中,将 unidbg_url 的 IP 地址改为服务名 unidbg_boot_server - 修改 unidbg_boot_server/Dockerfile,将暴露的端口从 8080 改为 9999
550 lines
20 KiB
Python
550 lines
20 KiB
Python
import ctypes
|
||
import hashlib
|
||
import json
|
||
import time
|
||
import traceback
|
||
from urllib.parse import parse_qs
|
||
import logging
|
||
import logging.config
|
||
import os
|
||
|
||
import requests
|
||
from flask import Flask, request, jsonify
|
||
from flask_cors import CORS
|
||
|
||
from logger import get_logger
|
||
from spider import AppStoreSpider, GoodsAppleCard, GameArea, DeleteOrder, LoginSpider
|
||
|
||
app = Flask(__name__)
|
||
# 跨域
|
||
CORS(app)
|
||
# 配置日志
|
||
logging.config.fileConfig('logging.conf')
|
||
logger = logging.getLogger('app')
|
||
|
||
|
||
# 苹果权益充值
|
||
@app.route('/jd/app/store', methods=['GET', 'POST'], strict_slashes=False)
|
||
def app_store():
|
||
if request.method == 'GET':
|
||
return 'app_store'
|
||
elif request.method == 'POST':
|
||
# 接收参数
|
||
data = json.loads(request.get_data())
|
||
face_price = data.get("face_price")
|
||
order_num = data.get("order_num")
|
||
cookies = data.get("cookies")
|
||
# 打印参数日志
|
||
logger.info(f"订单ID:{order_num},cookies:{cookies}")
|
||
logger.info(f"订单ID:{order_num},card_pwd:{face_price}")
|
||
app_store = AppStoreSpider(
|
||
cookies=cookies,
|
||
face_price=face_price,
|
||
order_num=order_num
|
||
)
|
||
code, res = app_store.run()
|
||
item = {
|
||
"code": code,
|
||
"data": res
|
||
}
|
||
logger.info(f"订单ID:{order_num},最终返回日志:{item}")
|
||
# 打印响应日志
|
||
return jsonify(item)
|
||
|
||
|
||
# 查卡密
|
||
@app.route('/jd/query/card', methods=['GET', 'POST'], strict_slashes=False)
|
||
def query_card():
|
||
if request.method == 'GET':
|
||
return 'query_card'
|
||
elif request.method == 'POST':
|
||
# 接收参数
|
||
data = json.loads(request.get_data())
|
||
jd_order_num = data.get("jd_order_num")
|
||
cookies = data.get("cookies")
|
||
# 打印参数日志
|
||
logger.info(f"订单ID:{jd_order_num},cookies:{cookies}")
|
||
app_store = AppStoreSpider(
|
||
cookies=cookies,
|
||
order_num=jd_order_num
|
||
)
|
||
code, res = app_store.get_card_secret(jd_order_num)
|
||
item = {
|
||
"code": code,
|
||
"data": res
|
||
}
|
||
logger.info(f"订单ID:{jd_order_num},最终返回日志:{item}")
|
||
# 打印响应日志
|
||
return jsonify(item)
|
||
|
||
|
||
# 获取sku参数
|
||
@app.route('/jd/sku', methods=['GET', 'POST'], strict_slashes=False)
|
||
def game_area():
|
||
if request.method == 'GET':
|
||
return 'game_area'
|
||
elif request.method == 'POST':
|
||
data = json.loads(request.get_data())
|
||
cookies = data.get("cookies")
|
||
sku_id = data.get("sku_id")
|
||
details = GameArea.get_details(cookies, sku_id)
|
||
data = details.get("result", {})
|
||
item = {
|
||
"code": 100 if data else 110,
|
||
"data": data
|
||
}
|
||
return jsonify(item)
|
||
|
||
|
||
# 账号类下单
|
||
@app.route('/jd/goods/store', methods=['GET', 'POST'], strict_slashes=False)
|
||
def goods_store():
|
||
if request.method == 'GET':
|
||
return 'goods_store'
|
||
elif request.method == 'POST':
|
||
data = json.loads(request.get_data())
|
||
# 参数
|
||
face_price = data.get("face_price")
|
||
order_num = data.get("order_num")
|
||
cookies = data.get("cookies")
|
||
brand_id = data.get("brand_id")
|
||
sku_id = data.get("sku_id")
|
||
username = data.get("username")
|
||
game_srv = data.get("gamesrv")
|
||
game_area = data.get("gamearea")
|
||
# 类型 1:username账号充值,2:游戏区服充值
|
||
recharge_type = data.get("recharge_type")
|
||
# 打印参数日志
|
||
logger.info(f"订单ID:{order_num},cookies:{cookies}")
|
||
logger.info(f"订单ID:{order_num},card_pwd:{face_price}")
|
||
app_store = GoodsAppleCard(
|
||
cookies=cookies,
|
||
face_price=face_price,
|
||
order_num=order_num,
|
||
sku_id=sku_id,
|
||
brand_id=brand_id,
|
||
username=username,
|
||
game_srv=game_srv,
|
||
game_area=game_area,
|
||
recharge_type=recharge_type,
|
||
)
|
||
code, res = app_store.run()
|
||
item = {
|
||
"code": code,
|
||
"data": res
|
||
}
|
||
logger.info(f"订单ID:{order_num},goods_store最终返回日志:{item}")
|
||
# 打印响应日志
|
||
return jsonify(item)
|
||
|
||
|
||
def r(data_string):
|
||
def int_overflow(val):
|
||
maxint = 2147483647
|
||
if not -maxint - 1 <= val <= maxint:
|
||
val = (val + (maxint + 1)) % (2 * (maxint + 1)) - maxint - 1
|
||
return val
|
||
|
||
def unsigned_right_shitf(n, i):
|
||
# 数字小于0,则转为32位无符号uint
|
||
if n < 0:
|
||
n = ctypes.c_uint32(n).value
|
||
# 正常位移位数是为正数,但是为了兼容js之类的,负数就右移变成左移好了
|
||
if i < 0:
|
||
return -int_overflow(n << abs(i))
|
||
# print(n)
|
||
return int_overflow(n >> i)
|
||
|
||
char_list = []
|
||
aae = ['K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'U', 'V',
|
||
'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'e', 'f', 'g', 'h',
|
||
'i', 'j', 'k', 'l', 'm', 'n', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/']
|
||
bArr = data_string.encode('utf-8')
|
||
for i in range(0, len(bArr), 3):
|
||
bArr2 = [None for i in range(4)]
|
||
b2 = 0
|
||
for i2 in range(0, 3):
|
||
i3 = i + i2
|
||
if i3 <= len(bArr) - 1:
|
||
bArr2[i2] = b2 | unsigned_right_shitf((bArr[i3] & 255), ((i2 * 2) + 2))
|
||
b2 = unsigned_right_shitf(((bArr[i3] & 255) << (((2 - i2) * 2) + 2)) & 255, 2)
|
||
else:
|
||
bArr2[i2] = b2
|
||
b2 = 64
|
||
bArr2[3] = b2
|
||
for i4 in range(4):
|
||
if bArr2[i4] <= 63:
|
||
char_list.append(aae[bArr2[i4]])
|
||
else:
|
||
char_list.append("=")
|
||
|
||
return "".join(char_list)
|
||
|
||
|
||
def encode_cipher(cipher_dict):
|
||
for k, v in cipher_dict.items():
|
||
cipher_dict[k] = r(v)
|
||
|
||
|
||
def gen_cipher_ep(uuid, ts):
|
||
"""
|
||
|
||
:param uid:
|
||
:param aid:
|
||
:param open_udid:
|
||
:param ts:
|
||
:return:
|
||
"""
|
||
cipher_dict = {
|
||
"d_model": "SM-N9760",
|
||
"wifiBssid": "unknown",
|
||
"osVersion": "9",
|
||
"d_brand": "samsung",
|
||
"screen": "960*540",
|
||
"uuid": uuid,
|
||
"aid": uuid,
|
||
}
|
||
encode_cipher(cipher_dict)
|
||
data_dict = {
|
||
"hdid": "JM9F1ywUPwflvMIpYPok0tt5k9kW4ArJEU3lfLhxBqw=",
|
||
"ts": ts,
|
||
'ridx': -1,
|
||
'cipher': cipher_dict,
|
||
'ciphertype': 5,
|
||
"version": "1.2.0",
|
||
'appname': "com.jingdong.app.mall"
|
||
}
|
||
ep = json.dumps(data_dict, separators=(',', ':'))
|
||
|
||
return ep
|
||
|
||
|
||
def get_pay_sign(order_id, face_price):
|
||
app_id = "jd_android_app4"
|
||
pay_app_key = "e53jfgRgd7Hk"
|
||
input_str = f"{app_id};{order_id};37;{face_price};{pay_app_key}"
|
||
# 获取 MD5 实例
|
||
input_bytes = input_str.encode("GBK")
|
||
md5_hash = hashlib.md5()
|
||
md5_hash.update(input_bytes)
|
||
return md5_hash.hexdigest()
|
||
|
||
|
||
def get_sign(func, body, uuid, version):
|
||
headers_jd = {
|
||
'Content-Type': 'application/json'
|
||
}
|
||
payload = json.dumps({
|
||
"func": func,
|
||
"body": body,
|
||
"uid": uuid,
|
||
"platform": "android",
|
||
"version": version
|
||
})
|
||
unidbg_url = "http://unidbg_boot_server:9999/api/jd/encrypt"
|
||
response_jd = requests.request("POST", url=unidbg_url, headers=headers_jd, data=payload)
|
||
res = response_jd.json()
|
||
params = parse_qs(res["data"])
|
||
formatted_params = {key: value[0] for key, value in params.items()}
|
||
return formatted_params
|
||
|
||
|
||
def my_json(code, data, msg):
|
||
return {
|
||
"code": code,
|
||
"data": data,
|
||
"msg": msg
|
||
}
|
||
|
||
|
||
@app.route('/api/v1/jd/wx/plat_pay_channel', methods=["GET", "POST"], strict_slashes=False)
|
||
def plat_pay_channel():
|
||
if request.method == "GET":
|
||
return "okk"
|
||
elif request.method == "POST":
|
||
import uuid
|
||
# 接收参数
|
||
data = json.loads(request.get_data())
|
||
app.logger.info(f"接收到的请求数据: {data}")
|
||
# 获取数据
|
||
order_id = data.get("order_id")
|
||
face_price = data.get("face_price")
|
||
face_price = str("{:.2f}".format(float(face_price)))
|
||
pay_id = data.get("pay_id")
|
||
cookies = data.get("cookies")
|
||
|
||
# 打印日志
|
||
app.logger.info(f"获取微信app端支付参数")
|
||
app.logger.info(f"cookie:{cookies}")
|
||
app.logger.info(f"order_id:{order_id}")
|
||
app.logger.info(f"face_price:{face_price}")
|
||
app.logger.info(f"pay_id:{pay_id}")
|
||
|
||
headers = {
|
||
"Host": "api.m.jd.com",
|
||
"charset": "UTF-8",
|
||
"user-agent": "okhttp/3.12.1;jdmall;android;version/11.1.0;build/98139",
|
||
"cache-control": "no-cache",
|
||
"content-type": "application/x-www-form-urlencoded; charset=UTF-8",
|
||
"cookie": cookies
|
||
}
|
||
url = "https://api.m.jd.com/client.action"
|
||
func = "platPayChannel"
|
||
version = "11.1.0"
|
||
uuid = str(uuid.uuid4()).replace("-", "")
|
||
ts = int(time.time() * 1000)
|
||
ep = gen_cipher_ep(uuid, ts)
|
||
pay_sign = get_pay_sign(order_id=order_id, face_price=face_price)
|
||
body = '{"appId":"jd_android_app4","client":"android","fk_aid":"%s","fk_appId":"com.jingdong.app.mall","fk_latitude":"NfUaIOrNMes=","fk_longtitude":"NfUaIOrNMes=","fk_terminalType":"02","fk_traceIp":"26.26.26.1","hasCyberMoneyPay":"0","hasHuaweiPay":"0","hasOCPay":"0","hasUPPay":"0","orderId":"%s","orderPrice":"%s","orderType":"37","orderTypeCode":"0","origin":"native","payId":"%s","paySign":"%s","paySourceId":"2","payablePrice":"%s","sdkToken":"jdd016CSEHGQ3IPOGEXVOBUPDLTBSKZZUMESDDOP4PPRC2E2R7CC2K4LXQN63E6A3P3Y76GN4M5TMPIZGOWYQJG4MO6ET75VQFVQL2MIYRFQ01234567","source":"jdapp","style":"normal","supportNFC":"1"}' % (
|
||
uuid, order_id, face_price, pay_id, pay_sign, face_price
|
||
)
|
||
formatted_params = get_sign(func, body, uuid, version)
|
||
params = {
|
||
"functionId": func,
|
||
"clientVersion": version,
|
||
"build": "98139",
|
||
"client": "android",
|
||
"partner": "wandoujia",
|
||
# "eid": "eidAf760812200s2xOZPVA0sThGrvhABq1zrPMTmUOM1tv8FFg1FjE8yRJtYdV/UFhJuIkVZbrk/xl XPeoFQTNgMiYJpXeeyACCVPbt0/3R7R3Gd 8y",
|
||
"sdkVersion": "28",
|
||
"lang": "zh_CN",
|
||
"harmonyOs": "0",
|
||
"networkType": "wifi",
|
||
# "uts": "0f31TVRjBSsqndu4/jgUPz6uymy50MQJ8fZr7wet7pLPYx9jEXMpd8VCD64sq/eBbsH5zZBXnKZMkN1vxnjOrpfx7GiQBINsuAELLpjOiZsCHkTDoRW/d9talOxyn2bo1YZLq8uq5Kdx/Fd7diA023Qwr+5V5TzeOnca3cc6QzMFh8p+DS2gR6Bimgz0BiNqbeN1q1NA9rJ/t5QOAIH9EA==",
|
||
"uemps": "0-0",
|
||
"ext": "{\"prstate\":\"0\",\"pvcStu\":\"1\"}",
|
||
"ef": "1",
|
||
"ep": ep,
|
||
"st": formatted_params["st"],
|
||
"sign": formatted_params["sign"],
|
||
"sv": formatted_params["sv"]
|
||
}
|
||
data = {
|
||
"body": body,
|
||
"": ""
|
||
}
|
||
client_res = None
|
||
# try:
|
||
response = requests.post(
|
||
url=url,
|
||
params=params,
|
||
headers=headers,
|
||
data=data
|
||
)
|
||
client_res = response.json()
|
||
app.logger.info(f"订单id:{order_id},获取支付参数res返回:{client_res}")
|
||
# except Exception as e:
|
||
# app.logger.info(traceback.format_exc())
|
||
# 不支持该支付类型
|
||
if client_res.get("errorCode") == "-2":
|
||
return my_json(code=20014, data={}, msg="订单类型不支持")
|
||
# ck失效
|
||
if client_res.get("errorCode") == "3":
|
||
return my_json(code=20002, data={}, msg="ck失效")
|
||
# 订单失效
|
||
if client_res.get("errorCode") == "-3":
|
||
return my_json(code=20005, data={}, msg="订单失效")
|
||
# 订单与下单账号不同
|
||
if client_res.get("errorCode") == "-5":
|
||
return my_json(code=20015, data={}, msg="订单与下单账号不匹配")
|
||
# 订单已取消
|
||
if client_res.get("errorCode") == "-100":
|
||
return my_json(code=20006, data={}, msg="订单已支付完成或已取消")
|
||
# 订单已支付完成或已取消
|
||
if client_res.get("mcashierConfirmInfo", {}).get("errorCode", "") == "-100":
|
||
return my_json(code=20006, data={}, msg="订单已支付完成或已取消")
|
||
# 获取微信支付参数
|
||
url = "https://api.m.jd.com/client.action"
|
||
headers = {
|
||
"Host": "api.m.jd.com",
|
||
"charset": "UTF-8",
|
||
"user-agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 16_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.6 Mobile/15E148 Safari/604.1",
|
||
"cache-control": "no-cache",
|
||
"content-type": "application/x-www-form-urlencoded; charset=UTF-8",
|
||
"cookie": cookies
|
||
}
|
||
import uuid
|
||
uuid = str(uuid.uuid4()).replace("-", "")
|
||
ts = int(time.time() * 1000)
|
||
ep = gen_cipher_ep(uuid, ts)
|
||
pay_sign = get_pay_sign(order_id=order_id, face_price=face_price)
|
||
sdk_token = "jdd01XYE6SS5ZXXG7F74OZC3PKG5LWF7W3GTVLTSUH56A2YAUXOT6NEEX4TRT3I3XDDYO7NQSIV4BSK3XGKWMROTBRKO4ENETDD4IEHFWZHA01234567"
|
||
body = '{"appId":"jd_android_app4","backUrl":"","client":"android","orderId":"%s","orderPrice":"%s","orderType":"37","orderTypeCode":"0","origin":"native","payId":"%s","paySign":"%s","sdkToken":"%s","source":"jdapp"}' % (
|
||
order_id, face_price, pay_id, pay_sign, sdk_token)
|
||
func = "platWXPay"
|
||
version = "11.0.0"
|
||
formatted_params = get_sign(func, body, uuid, version)
|
||
params = {
|
||
"functionId": "platWXPay",
|
||
"clientVersion": "11.0.0",
|
||
# "build": "97235",
|
||
"client": "android",
|
||
"partner": "huawei",
|
||
# "eid": "eidAd2c08121b3s9eOeub59TR2G1LS3GtRpmFHjnr/5tBkXKUdbZOahaF5ejedAIDQFfwVV2GDYUzftxnEQRjdhD5bpPNR4B0qK9tPJ 5liDjiHAhDR3",
|
||
"sdkVersion": "28",
|
||
"lang": "zh_CN",
|
||
"harmonyOs": "0",
|
||
"networkType": "wifi",
|
||
# "uts": "0f31TVRjBSsqndu4/jgUPz6uymy50MQJVJk5AARu8sQVESbyLWRZZNMf5XbN+023PgE2PL4I0aLSvISDbN3u1a1oIB1KTvzrqacX+46wkkSjXxvvYKogR9YCbfnMf2pdC5H/VDcJc2u6uHTxPVwvhLoJ8vX8cN45ZijAbikou9B5o2KTvMTzCfrSYgi3+mls/cA+6k+Ao5sFIIdtimZ6bw==",
|
||
"uemps": "0-0",
|
||
"ext": "{\"prstate\":\"0\",\"pvcStu\":\"1\"}",
|
||
"ef": "1",
|
||
"ep": ep,
|
||
"st": formatted_params["st"],
|
||
"sign": formatted_params["sign"],
|
||
"sv": formatted_params["sv"]
|
||
}
|
||
data = {
|
||
"body": body,
|
||
}
|
||
pay_channel_res = None
|
||
for i in range(3):
|
||
try:
|
||
response = requests.post(
|
||
url=url,
|
||
params=params,
|
||
headers=headers,
|
||
data=data,
|
||
timeout=2
|
||
)
|
||
pay_channel_res = response.json()
|
||
print(pay_channel_res)
|
||
app.logger.info(f"订单id:{order_id},获取微信支付参数返回:{pay_channel_res}")
|
||
break
|
||
except Exception as e:
|
||
app.logger.info(traceback.format_exc())
|
||
continue
|
||
# 当前支付方式不可用,建议选择其他支付方式
|
||
if pay_channel_res.get("errorCode") == "-1":
|
||
return my_json(code=60001, data={}, msg="爬虫异常")
|
||
# 加密算法失效
|
||
if pay_channel_res.get("code") == "600":
|
||
return my_json(code=60001, data={}, msg="加密算法异常")
|
||
# 不支持该支付类型
|
||
if pay_channel_res.get("errorCode") == "-2":
|
||
return my_json(code=20014, data={}, msg="订单类型不支持")
|
||
# ck失效
|
||
if pay_channel_res.get("errorCode") == "3":
|
||
return my_json(code=20002, data={}, msg="ck失效")
|
||
# 订单失效
|
||
if pay_channel_res.get("errorCode") == "-3":
|
||
return my_json(code=20005, data={}, msg="订单失效")
|
||
# 订单与下单账号不同
|
||
if pay_channel_res.get("errorCode") == "-5":
|
||
return my_json(code=20015, data={}, msg="订单与下单账号不匹配")
|
||
# 订单已取消
|
||
if pay_channel_res.get("errorCode") == "-100":
|
||
return my_json(code=20006, data={}, msg="订单已支付完成或已取消")
|
||
# 订单已支付完成或已取消
|
||
if pay_channel_res.get("mcashierConfirmInfo", {}).get("errorCode", "") == "-100":
|
||
return my_json(code=20006, data={}, msg="订单已支付完成或已取消")
|
||
# 获取数据
|
||
pay_info = pay_channel_res["payInfo"]
|
||
item = {
|
||
"pay_order_id": pay_channel_res["payOrderId"],
|
||
"pay_id": pay_channel_res["payId"],
|
||
"ts": pay_info["timeStamp"],
|
||
"package_name": pay_info["package"],
|
||
"pay_enum": pay_info["payEnum"],
|
||
"jd_pay_id": pay_info["jdPayId"],
|
||
"sign": pay_info["sign"],
|
||
"pre_pay_id": pay_info["prepayId"],
|
||
"partner_id": pay_info["partnerId"],
|
||
"nonce_str": pay_info["nonceStr"],
|
||
}
|
||
print(item)
|
||
return my_json(
|
||
code=2000,
|
||
data=item,
|
||
msg="请求成功"
|
||
)
|
||
|
||
|
||
@app.route('/api/v1/jd/delete_order', methods=["GET", "POST"], strict_slashes=False)
|
||
def delete_order():
|
||
if request.method == "GET":
|
||
return "okk"
|
||
elif request.method == "POST":
|
||
# 接收参数
|
||
data = json.loads(request.get_data())
|
||
app.logger.info(f"接收到的请求数据: {data}")
|
||
# 获取数据
|
||
cookie = data.get("cookie")
|
||
order_id = data.get("order_id")
|
||
delete_res = DeleteOrder(
|
||
cookie=cookie,
|
||
order_id=order_id
|
||
).run()
|
||
if isinstance(delete_res.get("body"), bool):
|
||
code = 2000
|
||
else:
|
||
code = 2001
|
||
return my_json(
|
||
code=code,
|
||
data={},
|
||
msg="请求成功"
|
||
)
|
||
|
||
|
||
@app.route('/jd/sms/code', methods=["GET", "POST"], strict_slashes=False)
|
||
def get_code():
|
||
if request.method == "GET":
|
||
return "okk"
|
||
elif request.method == "POST":
|
||
data = json.loads(request.get_data())
|
||
# 参数
|
||
phone = data.get("phone")
|
||
res = LoginSpider(
|
||
phone=phone,
|
||
).run_send_code()
|
||
logger.info(f"发送验证码返回:{res}")
|
||
# 打印响应日志
|
||
return jsonify(res)
|
||
|
||
|
||
@app.route('/jd/sms/login', methods=["GET", "POST"], strict_slashes=False)
|
||
def sms_login():
|
||
if request.method == "GET":
|
||
return "okk"
|
||
elif request.method == "POST":
|
||
data = json.loads(request.get_data())
|
||
# 参数
|
||
phone = data.get("phone")
|
||
ck = data.get("ck")
|
||
code = data.get("code")
|
||
s_token = data.get("s_token")
|
||
jd_risk_token_id = data.get("jd_risk_token_id")
|
||
rsa_modulus = data.get("rsa_modulus")
|
||
res = LoginSpider(
|
||
phone=phone,
|
||
).run_get_ck(
|
||
ck=ck,
|
||
code=code,
|
||
s_token=s_token,
|
||
jd_risk_token_id=jd_risk_token_id,
|
||
rsa_modulus=rsa_modulus
|
||
)
|
||
logger.info(f"短信登录返回:{res}")
|
||
# 打印响应日志
|
||
return jsonify(res)
|
||
|
||
|
||
@app.route('/')
|
||
def index():
|
||
logger.info('访问首页')
|
||
return 'Hello World'
|
||
|
||
|
||
@app.route('/api/endpoint')
|
||
def api_endpoint():
|
||
try:
|
||
logger.info('处理API请求')
|
||
# ... existing code ...
|
||
except Exception as e:
|
||
logger.error(f'API请求处理失败: {str(e)}')
|
||
return {'error': str(e)}, 500
|
||
|
||
|
||
if __name__ == '__main__':
|
||
app.run(host="0.0.0.0", port=8289)
|