Hướng dẫn này trình bày toàn bộ quy trình: tải tệp cục bộ lên, xuất tệp từ Cloud Phone, thăm dò tác vụ bất đồng bộ và khôi phục sau khi hết thời gian chờ.
| Bước | Open API | Local API |
|---|---|---|
| Base URL | https://api.morelogin.com | http://127.0.0.1:40000 |
| Xác thực | Authorization: Bearer <token> | Local API token |
| Yêu cầu URL tải lên | POST /cloudphone/uploadUrl | POST /api/cloudphone/upload/file/signedUrl |
| Đăng ký đối tượng đã tải | POST /cloudphone/uploadFile | POST /api/cloudphone/upload/file |
| Truy vấn kết quả tải lên | POST /cloudphone/uploadFileResult | POST /api/cloudphone/upload/file/result |
| Yêu cầu xuất tệp | POST /cloudphone/download | POST /api/cloudphone/download |
| Truy vấn kết quả xuất | POST /cloudphone/download/result | POST /api/cloudphone/download/result |
Ví dụ dùng Open API. Với Local API, hãy đổi URL cơ sở và đường dẫn theo bảng. Giữ id, fileId và downId ở dạng chuỗi; JavaScript không được chuyển chúng qua Number.
Nếu tệp nằm trên cùng máy với ứng dụng MoreLogin, có thể gửi trực tiếp. Phản hồi thành công là đối tượng rỗng và không có ID tác vụ. Dùng quy trình URL ký sẵn nếu cần theo dõi và thử lại có thể quan sát.
curl --request POST "http://127.0.0.1:40000/api/cloudphone/uploadFile" \
--form 'id=1661515884160372' \
--form 'uploadDest=/Download' \
--form 'file=@./report.csv'curl --request POST "https://api.morelogin.com/cloudphone/uploadUrl" \
--header "Authorization: Bearer $MORELOGIN_TOKEN" \
--header "Content-Type: application/json" \
--data '{
"id": "1661515884160372",
"fileName": "report.csv"
}'curl --location --request PUT \
--upload-file "./report.csv" \
"$PRESIGNED_URL"FILE_URL="${PRESIGNED_URL%%\?*}"
curl --request POST "https://api.morelogin.com/cloudphone/uploadFile" \
--header "Authorization: Bearer $MORELOGIN_TOKEN" \
--header "Content-Type: application/json" \
--data "$(jq -n \
--arg id '1661515884160372' \
--arg url "$FILE_URL" \
--arg dest '/Download' \
'{id: $id, url: $url, uploadDest: $dest, uploadType: 1}')"curl --request POST "https://api.morelogin.com/cloudphone/uploadFileResult" \
--header "Authorization: Bearer $MORELOGIN_TOKEN" \
--header "Content-Type: application/json" \
--data '{
"id": "1661515884160372",
"fileId": "1661515884160111"
}'Lưu data.presignedUrl. Gửi tệp trực tiếp đến URL này mà không kèm Bearer token. Chỉ tiếp tục sau trạng thái HTTP thành công, đăng ký URL đối tượng và lưu data.fileId.
data / data.status | Ý nghĩa | Xử lý |
|---|---|---|
null | Tác vụ chưa hiển thị | Chờ rồi truy vấn lại |
0 | Đang tải lên | Chờ rồi truy vấn lại |
1 | Thành công | Dừng truy vấn |
2 | Thất bại | Dừng và báo requestId |
Tải xuống là xuất tệp từ Cloud Phone sang URL tạm thời. Lưu data.downId và truy vấn cho đến trạng thái kết thúc.
curl --request POST "https://api.morelogin.com/cloudphone/download" \
--header "Authorization: Bearer $MORELOGIN_TOKEN" \
--header "Content-Type: application/json" \
--data '{
"id": "1661515884160372",
"filePath": "/sdcard/Download/report.csv"
}'curl --request POST "https://api.morelogin.com/cloudphone/download/result" \
--header "Authorization: Bearer $MORELOGIN_TOKEN" \
--header "Content-Type: application/json" \
--data '{
"id": "1661515884160372",
"downId": "1661515884160999"
}'data.status | Ý nghĩa | Xử lý |
|---|---|---|
10 | Đang chạy | Chờ rồi truy vấn lại |
20 | Thành công | Tải từ data.downUrl |
30 | Thất bại | Dừng và báo requestId |
40 | Đã hủy | Dừng; chỉ tạo tác vụ mới khi vẫn cần |
curl --location "$DOWN_URL" --output "./report.csv"Ví dụ kiểm tra HTTP và code nghiệp vụ, tái sử dụng ID tác vụ và đặt hạn chót thăm dò.
import os
import time
from pathlib import Path
import requests
BASE_URL = "https://api.morelogin.com"
TOKEN = os.environ["MORELOGIN_TOKEN"]
PHONE_ID = "1661515884160372"
HEADERS = {"Authorization": f"Bearer {TOKEN}"}
def api_post(path, payload):
response = requests.post(
f"{BASE_URL}{path}", json=payload, headers=HEADERS, timeout=30
)
response.raise_for_status()
body = response.json()
if body.get("code") != 0:
raise RuntimeError(
f"API error code={body.get('code')} msg={body.get('msg')} "
f"requestId={body.get('requestId')}"
)
return body
def wait_for(path, payload, terminal, timeout=300):
deadline = time.monotonic() + timeout
while time.monotonic() < deadline:
body = api_post(path, payload)
data = body.get("data")
if data is not None and data.get("status") in terminal:
return body
time.sleep(2)
raise TimeoutError(f"Timed out while polling {path}; keep the task ID")
def upload_to_phone(local_path, destination="/Download"):
path = Path(local_path)
signed = api_post(
"/cloudphone/uploadUrl", {"id": PHONE_ID, "fileName": path.name}
)
presigned_url = signed["data"]["presignedUrl"]
with path.open("rb") as stream:
put_response = requests.put(presigned_url, data=stream, timeout=120)
put_response.raise_for_status()
object_url = presigned_url.split("?", 1)[0]
created = api_post(
"/cloudphone/uploadFile",
{
"id": PHONE_ID,
"url": object_url,
"uploadDest": destination,
"uploadType": 1,
},
)
file_id = created["data"]["fileId"]
result = wait_for(
"/cloudphone/uploadFileResult",
{"id": PHONE_ID, "fileId": file_id},
terminal={1, 2},
)
if result["data"]["status"] != 1:
raise RuntimeError(f"Upload failed; requestId={result.get('requestId')}")
return file_id
def download_from_phone(remote_path, local_path):
created = api_post(
"/cloudphone/download", {"id": PHONE_ID, "filePath": remote_path}
)
down_id = created["data"]["downId"]
result = wait_for(
"/cloudphone/download/result",
{"id": PHONE_ID, "downId": down_id},
terminal={20, 30, 40},
)
if result["data"]["status"] != 20:
raise RuntimeError(f"Download export failed; requestId={result.get('requestId')}")
with requests.get(result["data"]["downUrl"], stream=True, timeout=120) as response:
response.raise_for_status()
with open(local_path, "wb") as output:
for chunk in response.iter_content(1024 * 1024):
if chunk:
output.write(chunk)
return down_id
upload_to_phone("./report.csv")
download_from_phone("/sdcard/Download/report.csv", "./downloaded-report.csv")- Xác nhận code == 0; chỉ HTTP 200 không chứng minh nghiệp vụ thành công.
- Giữ ID dạng chuỗi và truy vấn trạng thái trước khi lặp lại thao tác ghi sau timeout.
- Không ghi token hoặc URL ký sẵn vào log; giữ requestId để hỗ trợ.
- Giới hạn số truyền đồng thời và tuân thủ giới hạn yêu cầu.