Skip to content

Muvaffaqiyatlar va veb-hokiklar

O'yin (video, rasm, musiqa) * asynchronoz*: siz taskin (ijod) ni yaratasiz va natija tayyor bo'lganda olib ketasiz. Tasavvur qilish) va webhuk (tushirish) bilan tugallangan vazifalarni aniqlashning ikkita usuli mavjud: so'rovnoma* (so'rovnoma) va saytnoma* (tushish).

Muammoning hayot davri

POST /media/generate  →  status: processing  ──►  done   (result_url готов)
        │                                     └─►  failed (error, средства возвращены)
        └── (опционально) callback_url → пуш-вебхук на done/failed
  1. Tavsiyat. POST /media/generate model va parametrlari bilan id va so'rov uchun bog'liq bo'lgan ni qaytarib beradi:
json
{ "id": "beefb531-…", "model": "image/nano-banana-2", "status": "processing",
  "poll": "https://nordrouter.com/media/job/beefb531-…" }
  1. Tashkilot. Muammoni bajarish processingdone (yoki failed).

  2. Nomur. Bajarilgan vazifa result_url (nordrouter.com) ga bog'liq) bilan to'ldirilgan; fayl cheklangan vaqt saqlanadi (retention_days GET /media/models) Uni saqlash uchun yuklab oling.

Javobning formatini GET /media/job/:id (va veb-xokning jismlari) quyidagicha ko'rish mumkin:

json
{ "id": "beefb531-…", "status": "done",
  "result_url": "https://nordrouter.com/media/file/beefb531-…",
  "cost_usd": 0.052, "error": null }
  • statusprocessing | done | failed.
  • result_url faqat doneda to'ldiriladi, agar yo'q bo'lsa nullda to'ldiriladi.
  • result_url_2 Musiqa modellarining (Suno) ikkinchi treki, boshqacha null.
  • cost_usd haqiqiy qiymat (faxt bo'yicha ro'yxatga olinadi; muvaffaqiyatsiz ishlab chiqarilgan tariflanmaydi zaxira qaytariladi).
  • error failedda xato matni, agar yo'q bo'lsa nullda xato matni.

1. usul. So'rovnoma (so'rovnoma)

Eng oson yo'l - vaqti-vaqti bilan so'rash. GET /media/job/:idHozircha status bo'lmaydi. done/failed:

bash
curl https://nordrouter.com/media/job/beefb531-…

So'rov har 23 soniyada bir marta o'tkaziladi.So'rov har doim ishlaydi va ommaviy manzilni talab qilmaydi.Skriptlar, noutbuklar, CI uchun mos keladi.

2-taxt. veb-hukki (tush)

So'rovni o'tkazmaslik uchun callback_url ni POST /media/generate ga yuboring va vazifa tugallanganida biz POSTni o'zimiz yuboramiz:

bash
curl https://nordrouter.com/media/generate \
  -H "Authorization: Bearer sk-nr-YOUR-KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "image/nano-banana-2",
    "input": { "prompt": "…" },
    "callback_url": "https://your-server.com/webhooks/nordrouter",
    "callback_secret": "любая-ваша-строка"
  }'

Agar callback_url qabul qilinsa, yaratishga javob "webhook": "registered" ni o'z ichiga oladi. callback_url vazifa yaratishda birdan **** tekshirilgan: agar u mos kelmasa (https emas, xususiy/lokal manzil) so'rov 400 ni sabab bilan qaytaradi, vazifa yaratilmaydi.

Vebhuqa tanasi

Muammoni done/failed ga yetkazganida, sizning callback_url ga POST bilan bir xil jism bilan keladi, GET /media/job/:id bilan bir qatorda event sohasi.

json
{ "event": "media.completed", "id": "beefb531-…", "status": "done",
  "result_url": "https://nordrouter.com/media/file/beefb531-…",
  "cost_usd": 0.052, "error": null }
  • event media.completed (success) yoki media.failed (o'rtoq).

Imzolarni tekshirish

Agar siz callback_secret ga kirgan bo'lsangiz, X-NR-Signature sarlavhasida sha256=<hmac> HMAC-SHA256 so'rovning xom ostiga qo'yilgan, kalit = siringiz bor.

python
import hmac, hashlib

def verify(raw_body: bytes, header: str, secret: str) -> bool:
    expected = "sha256=" + hmac.new(secret.encode(), raw_body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, header)  # сравнение за константное время
javascript
import crypto from "node:crypto";
function verify(rawBody, header, secret) {
  const expected = "sha256=" + crypto.createHmac("sha256", secret).update(rawBody).digest("hex");
  return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(header));
}

HMACni baytlardan boshlab, xuddi kelganidek hisoblang, JSON-parsingga qadar o'qing, aks holda imzo o'zgarmaydi.

10 satr ichida tayyor qabul qiluvchi

Veb-hokni qabul qiladigan ishchi server imzoni tekshiradi va javob beradi 2xx. sir siz callback_secretga o'tkazilgan sirga o'xshaydi.

Node.js / Express:

javascript
import express from "express";
import crypto from "node:crypto";

const SECRET = "любая-ваша-строка";           // = ваш callback_secret
const app = express();

app.post("/webhooks/nordrouter",
  express.raw({ type: "application/json" }),   // сырое тело — обязательно для подписи
  (req, res) => {
    const expected = "sha256=" + crypto.createHmac("sha256", SECRET).update(req.body).digest("hex");
    const got = req.headers["x-nr-signature"] || "";
    if (expected.length !== got.length || !crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(got)))
      return res.sendStatus(401);             // подпись не сошлась — не наш запрос
    const job = JSON.parse(req.body);
    if (job.event === "media.completed") console.log("готово:", job.result_url, "$" + job.cost_usd);
    res.sendStatus(200);                       // ответьте 2xx, иначе будет повтор
  });

app.listen(3000);

Python / FastAPI:

python
import hmac, hashlib
from fastapi import FastAPI, Request, Response

SECRET = b"любая-ваша-строка"                  # = ваш callback_secret
app = FastAPI()

@app.post("/webhooks/nordrouter")
async def hook(request: Request):
    raw = await request.body()                 # сырые байты — обязательно для подписи
    expected = "sha256=" + hmac.new(SECRET, raw, hashlib.sha256).hexdigest()
    if not hmac.compare_digest(expected, request.headers.get("X-NR-Signature", "")):
        return Response(status_code=401)       # подпись не сошлась — не наш запрос
    job = await request.json()
    if job["event"] == "media.completed":
        print("готово:", job["result_url"], "$", job["cost_usd"])
    return Response(status_code=200)           # ответьте 2xx, иначе будет повтор

Mahalliy ravishda tekshirish

callback_url ommaviy bo'lishi kerak https. Yozatuv uchun noutbukda tunnelni ko'taring, masalan, ngrok http 3000 va unga berilgan https-manzilni callback_url. sifatida yuboring.

Etkazib berish va ishonchlilik

  • To'rtta urinishgacha (≈3 → 6 → 9 c), har bir 15 c vaqtga qadar. 2xxga javob bering, aks holda takrorlanadi.
  • Yo'llanmalar ** yo'q ** yo'llanmalar ** yo'q ** yo'q to'g'ridan-to'g'ri javob bering callback_url.
  • best-effort: agar to'rtta urinish ham muvaffaqiyatsiz tugasa (serveringiz yotgan), veb-hok no keyinroq qayta yuboriladi.

Veb-xukkalar so'rovnoma o'rniga o'tirmaydi.

Vebhuk tezlashtirish, kafolat emas. GET /media/job/:id Agar pul o'z vaqtida kelmasa, o'zingiz statusni so'rang. id.

Talablar callback_url

  • Faqat https:// bilan.
  • Faqatgina ommaviy** manzil. Mahalliy va xususiy manzillar (localhost, *.local, 10.x, 172.16–31.x, 192.168.x, 127.x, 169.254.x, 100.64–127.x, IPv6 loopback/ULA/link-local) ** Manzillar rad etiladi** bu SSRF himoyasi. Bu SSRF himoyasi.

Nima tanlash kerak?

So'rovVeb-xo'k
Ochiq https-manzilkerak emaskerak emas kerak
So'rovlar davrasidan oldinni olishni kechiktirishdeyarli darhol
Kezlatmasiz nazorat qilasizbest-effort + so'rovni ehtiyot sifatida nazorat qilasiz
Har qanday qulay joydaskriptlari, CI, noutbukserverlari, produkshn-bakendlar

Tavsiya: orqa tomonda veb-huq + sug'urta sifatida so'rovnoma; skript/notabda shunchaki so'rovnoma.