Proxy nội bộ — sẵn sàng xài
Worker đang chạy 24/7 trên Cloudflare Edge toàn cầu. Không cần deploy, không cần config — chỉ cần gọi URL.
Proxy nội bộ cho các dự án bóng đá. Chỉ cần gọi URL, không cần đăng ký API key bên thứ ba. Dữ liệu được cache thông minh trên Cloudflare Edge.
https://football-proxy-internal.manhpd-football.workers.dev
Chỉ cần 1 thông tin duy nhất: Base URL. Gọi API ngay, không cần cài đặt gì thêm.
https://football-proxy-internal.manhpd-football.workers.dev
Cloudflare Worker hoạt động như reverse proxy với cache layer, đứng giữa client app và API-Football.
App gửi request GET trực tiếp đến Worker URL
Worker kiểm tra Cloudflare KV xem dữ liệu đã được cache chưa
Nếu cache còn fresh, trả response ngay lập tức (< 10ms)
Nếu cache hết hạn, Worker forward request đến API-Football với API key
Lưu response vào KV với TTL phù hợp, trả kết quả cho client
Tất cả response từ API đều sử dụng cùng một cấu trúc wrapper. Dữ liệu thực tế nằm trong trường response.
{ "get": "fixtures", "parameters": { "live": "all" }, "errors": [], "results": 10, "paging": { "current": 1, "total": 1 }, "response": [ ... ] ← dữ liệu thực tế }
| Field | Type | Mô tả |
|---|---|---|
get | string | Tên endpoint đã gọi |
parameters | object | Các query params đã gửi |
errors | array | Danh sách lỗi (rỗng = OK) |
results | integer | Số kết quả trong response |
paging | object | Thông tin phân trang (current, total) |
response | array | Dữ liệu thực tế — mảng các object |
/fixtures?live=all
Lấy danh sách trận đấu. Hỗ trợ nhiều filter: trận đang diễn ra (live), theo ngày, theo giải đấu, theo đội, theo ID.
| Param | Type | Required | Mô tả |
|---|---|---|---|
live | string | optional | "all" = tất cả trận đang diễn ra |
date | string | optional | Lọc theo ngày, format YYYY-MM-DD |
id | int | optional | Fixture ID cụ thể |
league | int | optional | League ID — lọc theo giải đấu |
season | int | optional | Mùa giải (VD: 2024) |
team | int | optional | Team ID — lọc theo đội |
next | int | optional | N trận tiếp theo (kết hợp team/league) |
last | int | optional | N trận gần nhất (kết hợp team/league) |
{ "fixture": { "id": 1517580, "referee": "John Smith", "timezone": "UTC", "date": "2026-06-27T08:30:00+00:00", "timestamp": 1782549000, "periods": { "first": 1782549000, "second": null }, "venue": { "id": 556, "name": "Old Trafford", "city": "Manchester" }, "status": { "long": "First Half", "short": "1H", "elapsed": 14, "extra": null } }, "league": { "id": 39, "name": "Premier League", "country": "England", "logo": "https://media.api-sports.io/football/leagues/39.png", "flag": "https://media.api-sports.io/flags/gb-eng.svg", "season": 2024, "round": "Regular Season - 21" }, "teams": { "home": { "id": 33, "name": "Manchester United", "logo": "https://media.api-sports.io/football/teams/33.png", "winner": null }, "away": { "id": 40, "name": "Liverpool", "logo": "https://media.api-sports.io/football/teams/40.png", "winner": null } }, "goals": { "home": 2, "away": 1 }, "score": { "halftime": { "home": 1, "away": 0 }, "fulltime": { "home": 2, "away": 1 }, "extratime": { "home": null, "away": null }, "penalty": { "home": null, "away": null } } }
| Field | Type | Mô tả |
|---|---|---|
fixture.id | int | ID trận đấu |
fixture.referee | string|null | Trọng tài |
fixture.timezone | string | Múi giờ |
fixture.date | string | Thời gian ISO 8601 |
fixture.timestamp | int | Unix timestamp |
fixture.periods.first | int|null | Timestamp bắt đầu hiệp 1 |
fixture.periods.second | int|null | Timestamp bắt đầu hiệp 2 |
fixture.venue.id | int | ID sân vận động |
fixture.venue.name | string | Tên sân |
fixture.venue.city | string | Thành phố |
fixture.status.long | string | Trạng thái đầy đủ |
fixture.status.short | string | Mã trạng thái viết tắt |
fixture.status.elapsed | int|null | Phút đã chơi |
fixture.status.extra | int|null | Phút bù giờ |
league.id | int | ID giải đấu |
league.name | string | Tên giải |
league.country | string | Quốc gia |
league.logo | string | URL logo giải đấu |
league.flag | string | URL cờ quốc gia |
league.season | int | Mùa giải |
league.round | string | Vòng đấu |
teams.home.id | int | ID đội nhà |
teams.home.name | string | Tên đội nhà |
teams.home.logo | string | URL logo đội nhà |
teams.home.winner | bool|null | Đội nhà thắng (null = chưa kết thúc) |
teams.away.id | int | ID đội khách |
teams.away.name | string | Tên đội khách |
teams.away.logo | string | URL logo đội khách |
teams.away.winner | bool|null | Đội khách thắng |
goals.home | int|null | Số bàn thắng đội nhà |
goals.away | int|null | Số bàn thắng đội khách |
score.halftime | object | Tỷ số hiệp 1 (home, away) |
score.fulltime | object | Tỷ số chung cuộc |
score.extratime | object | Tỷ số hiệp phụ |
score.penalty | object | Tỷ số loạt penalty |
TBD Chưa xác địnhNS Chưa bắt đầu1H Hiệp 1HT Giữa giờ2H Hiệp 2ET Hiệp phụBT Nghỉ hiệp phụP PenaltyFT Kết thúcAET KT sau hiệp phụPEN KT sau penaltySUSP Tạm hoãnINT Gián đoạnPST HoãnCANC HủyABD Hủy bỏAWD Xử thắngWO Bỏ cuộcLIVE Đang diễn ra/fixtures/events?fixture={id}
Lấy danh sách sự kiện của trận đấu: bàn thắng, thẻ phạt, thay người, VAR...
| Param | Type | Required | Mô tả |
|---|---|---|---|
fixture | int | required | Fixture ID |
{ "time": { "elapsed": 23, "extra": null }, "team": { "id": 33, "name": "Manchester United", "logo": "https://media.api-sports.io/football/teams/33.png" }, "player": { "id": 1234, "name": "Bruno Fernandes" }, "assist": { "id": 5678, "name": "Marcus Rashford" }, "type": "Goal", "detail": "Normal Goal", "comments": null }
| Field | Type | Mô tả |
|---|---|---|
time.elapsed | int | Phút diễn ra sự kiện |
time.extra | int|null | Phút bù giờ (nếu có) |
team.id | int | ID đội liên quan |
team.name | string | Tên đội |
team.logo | string | URL logo đội |
player.id | int | ID cầu thủ |
player.name | string | Tên cầu thủ |
assist.id | int|null | ID cầu thủ kiến tạo |
assist.name | string|null | Tên cầu thủ kiến tạo |
type | string | Loại sự kiện (Goal, Card, subst, Var) |
detail | string | Chi tiết sự kiện |
comments | string|null | Ghi chú bổ sung |
| type | detail values |
|---|---|
Goal | Normal Goal, Own Goal, Penalty, Missed Penalty |
Card | Yellow Card, Red Card, Second Yellow card |
subst | Substitution 1, Substitution 2, Substitution 3, Substitution 4, Substitution 5, Substitution 6 |
Var | Goal cancelled, Penalty confirmed |
/fixtures/lineups?fixture={id}
Lấy đội hình ra sân, đội hình dự bị, sơ đồ chiến thuật và huấn luyện viên.
| Param | Type | Required | Mô tả |
|---|---|---|---|
fixture | int | required | Fixture ID |
{ "team": { "id": 33, "name": "Manchester United", "logo": "https://media.api-sports.io/football/teams/33.png", "colors": { "player": { "primary": "#DA291C", "number": "#FFFFFF", "border": "#DA291C" }, "goalkeeper": { "primary": "#1E1E1E", "number": "#FFFFFF", "border": "#1E1E1E" } } }, "coach": { "id": 123, "name": "Erik ten Hag", "photo": "https://media.api-sports.io/football/coachs/123.png" }, "formation": "4-2-3-1", "startXI": [ { "player": { "id": 1, "name": "Onana", "number": 24, "pos": "G", "grid": "1:1" } } ], "substitutes": [ { "player": { "id": 2, "name": "Bayindir", "number": 1, "pos": "G", "grid": null } } ] }
| Field | Type | Mô tả |
|---|---|---|
team.id | int | ID đội |
team.name | string | Tên đội |
team.logo | string | URL logo |
team.colors.player | object | Màu áo cầu thủ (primary, number, border) |
team.colors.goalkeeper | object | Màu áo thủ môn |
coach.id | int | ID huấn luyện viên |
coach.name | string | Tên HLV |
coach.photo | string | URL ảnh HLV |
formation | string | Sơ đồ chiến thuật (VD: "4-2-3-1") |
startXI[].player.id | int | ID cầu thủ |
startXI[].player.name | string | Tên cầu thủ |
startXI[].player.number | int | Số áo |
startXI[].player.pos | string | Vị trí (G, D, M, F) |
startXI[].player.grid | string|null | Vị trí trên sân (row:col) |
substitutes | array | Cầu thủ dự bị (cùng cấu trúc) |
G Thủ mônD Hậu vệM Tiền vệF Tiền đạo/fixtures/statistics?fixture={id}
Lấy thống kê trận đấu: sút bóng, kiểm soát bóng, phạm lỗi, thẻ phạt, xG...
| Param | Type | Required | Mô tả |
|---|---|---|---|
fixture | int | required | Fixture ID |
{ "team": { "id": 33, "name": "Manchester United", "logo": "https://media.api-sports.io/football/teams/33.png" }, "statistics": [ { "type": "Shots on Goal", "value": 5 }, { "type": "Ball Possession", "value": "55%" }, { "type": "expected_goals", "value": "1.23" } ] }
| Field | Type | Mô tả |
|---|---|---|
team.id | int | ID đội |
team.name | string | Tên đội |
team.logo | string | URL logo |
statistics[].type | string | Tên thống kê |
statistics[].value | int|string|null | Giá trị thống kê |
Shots on GoalShots off GoalTotal ShotsBlocked ShotsShots insideboxShots outsideboxFoulsCorner KicksOffsidesBall PossessionYellow CardsRed CardsGoalkeeper SavesTotal passesPasses accuratePasses %expected_goalsgoals_preventedvalue có thể là int (VD: 5), string (VD: "55%"), hoặc null (chưa có dữ liệu)./fixtures/headtohead?h2h=33-40
Lấy lịch sử đối đầu giữa hai đội. Response trả về danh sách fixtures giống endpoint /fixtures.
| Param | Type | Required | Mô tả |
|---|---|---|---|
h2h | string | required | Format: TEAMID-TEAMID (VD: "33-40") |
/fixtures — mỗi item là một FixtureResponse object./featured?leagues=39,140,135&season=2024
Custom worker endpoint. Kết hợp 20 trận tiếp theo + 20 trận gần nhất cho mỗi giải đấu, loại bỏ trùng lặp. Phù hợp cho trang chủ app.
| Param | Type | Required | Mô tả |
|---|---|---|---|
leagues | string | optional | Danh sách League IDs, phân cách bởi dấu phẩy |
season | int | optional | Mùa giải (VD: 2024) |
/fixtures — mỗi item là một FixtureResponse object./standings?league=39&season=2024
Lấy bảng xếp hạng giải đấu. Kết quả nằm trong league.standings — là mảng các mảng (groups).
| Param | Type | Required | Mô tả |
|---|---|---|---|
league | int | required | League ID |
season | int | required | Mùa giải (VD: 2024) |
{ "league": { "id": 39, "name": "Premier League", "country": "England", "logo": "https://media.api-sports.io/football/leagues/39.png", "flag": "https://media.api-sports.io/flags/gb-eng.svg", "season": 2024, "standings": [[ { "rank": 1, "team": { "id": 40, "name": "Liverpool", "logo": "https://media.api-sports.io/football/teams/40.png" }, "points": 84, "goalsDiff": 45, "group": "Premier League", "form": "DLDLW", "status": "same", "description": "Champions League", "all": { "played": 38, "win": 25, "draw": 9, "lose": 4, "goals": { "for": 86, "against": 41 } }, "home": { "played": 19, "win": 14, "draw": 4, "lose": 1, "goals": { "for": 42, "against": 16 } }, "away": { "played": 19, "win": 11, "draw": 5, "lose": 3, "goals": { "for": 44, "against": 25 } }, "update": "2025-05-26T00:00:00+00:00" } ]] } }
| Field | Type | Mô tả |
|---|---|---|
league.id | int | ID giải đấu |
league.name | string | Tên giải |
league.country | string | Quốc gia |
league.season | int | Mùa giải |
league.standings | array[][] | Mảng 2 chiều — mỗi mảng con là 1 group |
rank | int | Thứ hạng |
team.id | int | ID đội |
team.name | string | Tên đội |
team.logo | string | URL logo |
points | int | Số điểm |
goalsDiff | int | Hiệu số bàn thắng |
group | string | Tên bảng/nhóm |
form | string | Phong độ 5 trận gần nhất (W/D/L) |
status | string | Thay đổi thứ hạng (same/up/down) |
description | string|null | Mô tả vị trí (Champions League, Relegation...) |
all | object | Thống kê tổng (played, win, draw, lose, goals) |
home | object | Thống kê sân nhà |
away | object | Thống kê sân khách |
goals.for | int | Số bàn ghi được |
goals.against | int | Số bàn thua |
update | string | Thời gian cập nhật gần nhất |
/teams?id=33
Lấy thông tin đội bóng và sân vận động.
| Param | Type | Required | Mô tả |
|---|---|---|---|
id | int | optional | Team ID |
search | string | optional | Tìm kiếm theo tên (tối thiểu 3 ký tự) |
{ "team": { "id": 33, "name": "Manchester United", "code": "MUN", "country": "England", "founded": 1878, "national": false, "logo": "https://media.api-sports.io/football/teams/33.png" }, "venue": { "id": 556, "name": "Old Trafford", "address": "Sir Matt Busby Way", "city": "Manchester", "capacity": 76212, "surface": "grass", "image": "https://media.api-sports.io/football/venues/556.png" } }
| Field | Type | Mô tả |
|---|---|---|
team.id | int | ID đội |
team.name | string | Tên đầy đủ |
team.code | string | Mã viết tắt (3 ký tự) |
team.country | string | Quốc gia |
team.founded | int | Năm thành lập |
team.national | bool | Đội tuyển quốc gia? |
team.logo | string | URL logo |
venue.id | int | ID sân |
venue.name | string | Tên sân |
venue.address | string | Địa chỉ |
venue.city | string | Thành phố |
venue.capacity | int | Sức chứa |
venue.surface | string | Bề mặt sân (grass, artificial turf...) |
venue.image | string | URL ảnh sân |
/leagues?country=England
Lấy thông tin giải đấu, quốc gia, và các mùa giải có sẵn. Không truyền param = lấy tất cả.
| Param | Type | Required | Mô tả |
|---|---|---|---|
id | int | optional | League ID cụ thể |
country | string | optional | Lọc theo quốc gia |
{ "league": { "id": 39, "name": "Premier League", "type": "League", "logo": "https://media.api-sports.io/football/leagues/39.png" }, "country": { "name": "England", "code": "GB-ENG", "flag": "https://media.api-sports.io/flags/gb-eng.svg" }, "seasons": [ { "year": 2024, "start": "2024-08-16", "end": "2025-05-25", "current": true, "coverage": { "fixtures": { "events": true, "lineups": true, "statistics_fixtures": true, "statistics_players": true }, "standings": true, "players": true, "top_scorers": true, "top_assists": true, "top_cards": true, "injuries": true, "predictions": true, "odds": false } } ] }
| Field | Type | Mô tả |
|---|---|---|
league.id | int | ID giải đấu |
league.name | string | Tên giải |
league.type | string | Loại: "League" hoặc "Cup" |
league.logo | string | URL logo |
country.name | string | Tên quốc gia |
country.code | string | Mã quốc gia |
country.flag | string | URL cờ |
seasons[].year | int | Năm mùa giải |
seasons[].start | string | Ngày bắt đầu |
seasons[].end | string | Ngày kết thúc |
seasons[].current | bool | Mùa giải hiện tại? |
coverage.fixtures | object | Dữ liệu fixtures có sẵn |
coverage.standings | bool | Có bảng xếp hạng? |
coverage.players | bool | Có thống kê cầu thủ? |
coverage.odds | bool | Có tỷ lệ kèo? |
/countries
Lấy danh sách tất cả quốc gia có giải đấu bóng đá. Không cần query params.
{ "name": "England", "code": "GB-ENG", "flag": "https://media.api-sports.io/flags/gb-eng.svg" }
| Field | Type | Mô tả |
|---|---|---|
name | string | Tên quốc gia |
code | string | Mã quốc gia (ISO) |
flag | string | URL cờ quốc gia (SVG) |
/timezone
Lấy danh sách tất cả timezone được API hỗ trợ. Response là mảng string đơn giản.
[ "Africa/Abidjan", "Africa/Accra", "America/New_York", "Asia/Ho_Chi_Minh", "Europe/London", "..." ]
/players/topscorers?league=39&season=2023
Lấy danh sách các cầu thủ ghi bàn / kiến tạo nhiều nhất của một giải đấu trong một mùa giải. Bạn có thể thay đổi endpoint thành /players/topassists, /players/topyellowcards, hoặc /players/topredcards để lấy thống kê tương ứng.
| Parameter | Type | Required | Description |
|---|---|---|---|
league |
Integer | Yes | ID của giải đấu (VD: 39 cho Premier League) |
season |
Integer | Yes | Năm bắt đầu của mùa giải (VD: 2023) |
| Field | Type | Description |
|---|---|---|
player.id | int | ID của cầu thủ |
player.name | string | Tên cầu thủ |
statistics[0].team.name | string | Tên đội bóng |
statistics[0].goals.total | int|null | Tổng số bàn thắng |
statistics[0].goals.assists | int|null | Tổng số kiến tạo |
statistics[0].cards.yellow | int|null | Số thẻ vàng |
statistics[0].cards.red | int|null | Số thẻ đỏ |
/injuries?fixture=1032731
Lấy danh sách các cầu thủ bị chấn thương, treo giò hoặc vắng mặt trong một trận đấu cụ thể (fixture), hoặc của một đội bóng.
| Parameter | Type | Required | Description |
|---|---|---|---|
fixture |
Integer | No | ID của trận đấu. Phải có ít nhất 1 tham số như fixture, team, hoặc league. |
team |
Integer | No | ID của đội bóng |
| Field | Type | Description |
|---|---|---|
player.id | int | ID của cầu thủ |
player.name | string | Tên cầu thủ |
player.type | string | Tình trạng (Missing Fixture, Questionable...) |
player.reason | string | Lý do (Ankle Injury, Suspended...) |
team.name | string | Tên đội bóng |
fixture.date | string | Ngày diễn ra trận đấu |
/transfers?team=33
Lấy lịch sử chuyển nhượng của một cầu thủ hoặc một đội bóng.
| Parameter | Type | Required | Description |
|---|---|---|---|
team |
Integer | No | ID của đội bóng (lấy danh sách chuyển nhượng của đội) |
player |
Integer | No | ID của cầu thủ (lấy lịch sử chuyển nhượng của cầu thủ) |
| Field | Type | Description |
|---|---|---|
player.name | string | Tên cầu thủ |
transfers[].date | string | Ngày chuyển nhượng |
transfers[].type | string | Loại chuyển nhượng (Free, Loan, € 50M...) |
transfers[].teams.in.name | string | Đội mua / mượn (đến) |
transfers[].teams.out.name | string | Đội bán / cho mượn (đi) |
/predictions?fixture=1208869
Lấy dữ liệu dự đoán, nhận định tỉ số, phong độ đối đầu và phân tích sức mạnh giữa hai đội trước một trận đấu.
| Parameter | Type | Required | Description |
|---|---|---|---|
fixture |
Integer | Yes | ID của trận đấu |
| Field | Type | Description |
|---|---|---|
predictions.winner.name | string | Tên đội dự đoán sẽ thắng |
predictions.advice | string | Lời khuyên / Nhận định chung (Tiếng Anh) |
predictions.percent.home | string | Tỉ lệ thắng của đội nhà (%) |
predictions.percent.draw | string | Tỉ lệ hòa (%) |
predictions.percent.away | string | Tỉ lệ thắng của đội khách (%) |
comparison.form.home | string | Chỉ số phong độ đội nhà |
comparison.total.home | string | Điểm sức mạnh tổng hợp đội nhà |
Ví dụ tích hợp đầy đủ cho các ngôn ngữ phổ biến. Copy & paste để bắt đầu ngay.
import Foundation
// MARK: - Configuration
let baseURL = "https://football-proxy-internal.manhpd-football.workers.dev"
// MARK: - API Client
func apiRequest(_ path: String) async throws -> Data {
guard let url = URL(string: "\(baseURL)\(path)") else {
throw URLError(.badURL)
}
var request = URLRequest(url: url)
request.timeoutInterval = 30
let (data, response) = try await URLSession.shared.data(for: request)
guard let httpResponse = response as? HTTPURLResponse,
(200...299).contains(httpResponse.statusCode) else {
throw URLError(.badServerResponse)
}
return data
}
// MARK: - Live Matches
func fetchLiveMatches() async throws -> [String: Any] {
let data = try await apiRequest("/fixtures?live=all")
guard let json = try JSONSerialization.jsonObject(with: data) as? [String: Any] else {
throw URLError(.cannotParseResponse)
}
return json
}
// MARK: - Standings
func fetchStandings(league: Int, season: Int) async throws -> Data {
return try await apiRequest("/standings?league=\(league)&season=\(season)")
}
// MARK: - Usage
Task {
do {
let matches = try await fetchLiveMatches()
print("Results: \(matches["results"] ?? 0)")
} catch {
print("Error: \(error.localizedDescription)")
}
}
import okhttp3.OkHttpClient
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import retrofit2.http.GET
import retrofit2.http.Query
// Configuration
const val BASE_URL = "https://football-proxy-internal.manhpd-football.workers.dev"
// API Interface
interface FootballApi {
@GET("/fixtures")
suspend fun getLiveMatches(@Query("live") live: String = "all"): ApiResponse
@GET("/standings")
suspend fun getStandings(
@Query("league") league: Int,
@Query("season") season: Int
): ApiResponse
@GET("/teams")
suspend fun getTeam(@Query("id") id: Int): ApiResponse
}
// Client Setup
val client = OkHttpClient.Builder()
.addInterceptor { chain ->
val request = chain.request().newBuilder()
.build()
chain.proceed(request)
}
.build()
val api: FootballApi = Retrofit.Builder()
.baseUrl(BASE_URL)
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(FootballApi::class.java)
// Usage
suspend fun main() {
try {
val matches = api.getLiveMatches()
println("Live: ${matches.results} matches")
} catch (e: Exception) {
println("Error: ${e.message}")
}
}
const BASE_URL = 'https://football-proxy-internal.manhpd-football.workers.dev';
// API Helper
async function api(path) {
const res = await fetch(`${BASE_URL}${path}`);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
return res.json();
}
// Live Matches
async function getLiveMatches() {
const data = await api('/fixtures?live=all');
console.log(`Live: ${data.results} matches`);
return data.response;
}
// Standings
async function getStandings(league, season) {
const data = await api(`/standings?league=${league}&season=${season}`);
return data.response;
}
// Usage
try {
const matches = await getLiveMatches();
const standings = await getStandings(39, 2024);
} catch (err) {
console.error('API Error:', err.message);
}
import 'dart:convert';
import 'package:http/http.dart' as http;
const baseUrl = 'https://football-proxy-internal.manhpd-football.workers.dev';
// API Helper
Future<Map<String, dynamic>> api(String path) async {
final response = await http.get(Uri.parse('$baseUrl$path'));
if (response.statusCode != 200) {
throw Exception('HTTP ${response.statusCode}');
}
return jsonDecode(response.body);
}
// ==========================================
// 1. DATA MODELS
// ==========================================
class Fixture {
final int id;
final String date;
final int timestamp;
final Status status;
Fixture.fromJson(Map json)
: id = json['id'],
date = json['date'],
timestamp = json['timestamp'],
status = Status.fromJson(json['status']);
}
class Status {
final String long;
final String short;
final int? elapsed;
Status.fromJson(Map json)
: long = json['long'],
short = json['short'],
elapsed = json['elapsed'];
}
class Team {
final int id;
final String name;
final String logo;
final bool? winner;
Team.fromJson(Map json)
: id = json['id'],
name = json['name'],
logo = json['logo'],
winner = json['winner'];
}
class FixtureMatch {
final Fixture fixture;
final Team home;
final Team away;
final int? homeGoals;
final int? awayGoals;
FixtureMatch.fromJson(Map json)
: fixture = Fixture.fromJson(json['fixture']),
home = Team.fromJson(json['teams']['home']),
away = Team.fromJson(json['teams']['away']),
homeGoals = json['goals']['home'],
awayGoals = json['goals']['away'];
}
// ==========================================
// 2. API CALLS
// ==========================================
Future<List<FixtureMatch>> getLiveMatches() async {
final response = await http.get(Uri.parse('$baseUrl/fixtures?live=all'));
if (response.statusCode == 200) {
final Map<String, dynamic> data = jsonDecode(response.body);
final List<dynamic> items = data['response'];
return items.map((e) => FixtureMatch.fromJson(e)).toList();
} else {
throw Exception('Failed to load matches');
}
}
// Usage
void main() async {
try {
final matches = await getLiveMatches();
for (var match in matches) {
print('${match.home.name} ${match.homeGoals} - ${match.awayGoals} ${match.away.name}');
}
} catch (e) {
print('Error: $e');
}
}
import requests
BASE = 'https://football-proxy-internal.manhpd-football.workers.dev'
def api(path):
"""Call Football API Proxy"""
r = requests.get(f'{BASE}{path}', timeout=30)
r.raise_for_status()
return r.json()
# Live Matches
def get_live_matches():
data = api('/fixtures?live=all')
print(f"Live: {data['results']} matches")
return data['response']
# Standings
def get_standings(league, season):
data = api(f'/standings?league={league}&season={season}')
return data['response']
# Usage
if __name__ == '__main__':
try:
matches = get_live_matches()
standings = get_standings(39, 2024)
except requests.RequestException as e:
print(f'Error: {e}')
# Configuration BASE="https://football-proxy-internal.manhpd-football.workers.dev" # Health Check curl -s "$BASE/__health" | jq . # Live Matches curl -s "$BASE/fixtures?live=all" | jq . # Standings curl -s "$BASE/standings?league=39&season=2024" | jq . # Teams curl -s "$BASE/teams?id=33" | jq . # With verbose output (see headers) curl -v "$BASE/fixtures?live=all" # Check cache headers curl -s -D- "$BASE/fixtures?live=all" | head -20
Hệ thống cache multi-layer sử dụng Cloudflare KV với Stale-While-Revalidate pattern.
| Endpoint | TTL | Grace Period | Total Edge TTL |
|---|---|---|---|
/fixtures (live) | 30s | 30s | 60s |
/fixtures (date/id) | 60s | 60s | 120s |
/fixtures/events | 60s | 60s | 120s |
/fixtures/lineups | 120s | 60s | 180s |
/fixtures/statistics | 60s | 60s | 120s |
/fixtures/headtohead | 3600s | 600s | 4200s |
/featured | 300s | 120s | 420s |
/standings | 900s | 300s | 1200s |
/teams | 86400s | 3600s | 90000s |
/leagues | 86400s | 3600s | 90000s |
/countries | 604800s | 86400s | 691200s |
/timezone | 604800s | 86400s | 691200s |
Khi cache fresh: trả về ngay, không gọi API gốc.
Khi cache stale (TTL hết nhưng còn trong grace period): trả về dữ liệu cũ ngay lập tức, đồng thời gọi API gốc để cập nhật cache ở background.
Khi cache expired (quá cả grace period): gọi API gốc, chờ response, lưu cache, rồi trả về.
| Header | Values | Mô tả |
|---|---|---|
X-Cache | HIT | MISS | Dữ liệu từ cache hay từ API gốc |
X-Cache-State | fresh | stale | expired | Trạng thái cache hiện tại |
X-Cache-TTL | number (seconds) | Số giây còn lại trước khi cache hết hạn |
4 lớp bảo mật bảo vệ Worker khỏi truy cập trái phép.
Firebase App Check xác minh request đến từ app hợp lệ, ngăn chặn bot và request giả mạo.
Chỉ các path được phép mới được proxy. Tất cả path khác trả về 403 Forbidden.
Chỉ cho phép request từ các origin đã được cấu hình. Ngăn chặn cross-origin request từ domain lạ.
Sử dụng Cloudflare Environments để quản lý nhiều dự án với cùng một codebase.
Mỗi project có thể có environment riêng trong wrangler.toml, với domain/subdomain riêng, KV namespace riêng, và API key riêng.
[env.livescore]
name = "football-proxy-livescore"
route = "livescore-proxy.example.com/*"
kv_namespaces = [
{ binding = "CACHE", id = "abc123" }
]
[env.betapp]
name = "football-proxy-betapp"
route = "betapp-proxy.example.com/*"
kv_namespaces = [
{ binding = "CACHE", id = "def456" }
]
wrangler deploy --env livescore3 bước để deploy Worker của riêng bạn.
git clone <repo-url>cd football-proxynpm install
wrangler loginnpm run secret
(Nhập API key từ api-football.com)
npm run deploy
Worker sẽ được deploy lên Cloudflare Edge toàn cầu.
Các lỗi thường gặp và cách khắc phục.
| Status | Nguyên nhân | Giải pháp |
|---|---|---|
401 |
Thiếu hoặc sai token | |
403 |
Path không được phép | Kiểm tra path có nằm trong allowlist không |
404 |
Endpoint không tồn tại | Kiểm tra lại URL, tham khảo API Reference |
429 |
Rate limit exceeded | Giảm tần suất gọi API, sử dụng cache phía client |
500 |
Lỗi server (Worker) | Kiểm tra logs với wrangler tail |
502 |
API-Football không phản hồi | Thử lại sau vài giây, kiểm tra API-Football status |
503 |
Service unavailable | Kiểm tra Cloudflare Status |
Các lệnh thường dùng khi phát triển và quản lý Worker.
| Lệnh | Mô tả |
|---|---|
npm install | Cài đặt dependencies |
npm run dev | Chạy local development server |
npm run deploy | Deploy Worker lên Cloudflare |
npm run tail | Xem logs realtime từ Worker đang chạy |
npm run secret | Set API key bí mật (API_FOOTBALL_KEY) |
wrangler whoami | Kiểm tra tài khoản Cloudflare đang đăng nhập |
wrangler kv:list | Liệt kê tất cả KV namespaces |
wrangler kv:key list --binding=CACHE | Xem danh sách keys trong cache KV |