Բոլոր դասերը
Վեբի հիմունքներՍկսնակ13 րոպե ընթերցումԻմ ստեկում

HTTP

Մեթոդներ, status code-եր, header-ներ, cookie-ներ, քեշավորում և CORS՝ raw օրինակներով։

  • Methods
  • Status codes
  • Headers
  • Cookies
  • Caching
  • CORS
Քայլ 1/6
API-ն մատուցողի նման է։ GET /menu՝ «բեր ինձ մենյուն», 200 OK, ահա։

30 վայրկյանում

HTTP-ն այն լեզուն է, որով խոսում են բրաուզերները, հավելվածները և սերվերները։ Client-ն ուղարկում է հարցում՝ մեթոդով, path-ով և header-ներով, սերվերը պատասխանում է status code-ով, header-ներով և body-ով։ Վեբում գրեթե ամեն ինչ՝ էջերից մինչև API-ներ և ֆայլերի ներբեռնումներ, կառուցված է այս պարզ հաղորդագրության ֆորմատի վրա, ուստի այն հասկանալը շատ է հեշտացնում debug-ը։

Ինչու եմ օգտագործում

  • Ամեն օր API-ներ և կայքեր եմ կառուցում, և բագերի մեծ մասն ակնհայտ է դառնում, երբ կարդում եմ raw հարցումն ու պատասխանը։
  • Ճիշտ status code-երը, header-ները և քեշավորումը հավելվածներն ավելի արագ ու անվտանգ են դարձնում՝ առանց լրացուցիչ կոդի։
  • Cookie-ների flag-երն ու CORS-ն այն տեղերն են, որտեղ թաքնված են անվտանգության և ինտեգրացիայի բազմաթիվ խնդիրներ։
  • Մոբայլ հավելվածները, ադմին պանելները և վեբ ֆրոնտենդները բոլորը խոսում են իմ բեքենդների հետ HTTP-ով, այնպես որ ընդհանուր ըմբռնումը ժամանակ է խնայում ամբողջ թիմի համար։

Ինչպես է աշխատում

01Հաղորդագրության ֆորմատը

HTTP-ն request–response պրոտոկոլ է, ինչպես մատուցողը, որն ընդունում է պատվերը և բերում ուտեստը։ Հարցումն ունի սկզբնական տող (մեթոդ, path, տարբերակ), header-ներ (key: value զույգեր) և ոչ պարտադիր body։ Պատասխանն ունի status տող (տարբերակ, կոդ, պատճառ), header-ներ և ոչ պարտադիր body։ HTTP-ն stateless է․ յուրաքանչյուր հարցում ինքնուրույն է, իսկ վիճակը, օրինակ՝ login-ը, փոխանցվում է cookie-ներով կամ token-ներով։ HTTP/2-ում և HTTP/3-ում նույն հաղորդագրություններն ուղարկվում են որպես բինար frame-եր, բայց իմաստը նույնն է, ուստի ներքևի տեքստային ձևը դեռ լավագույն միջոցն է դրանց մասին մտածելու համար։

http
POST /api/orders HTTP/1.1
Host: api.example.com
Content-Type: application/json
Authorization: Bearer <token>
Content-Length: 39
 
{"productId": 42, "quantity": 2}
 
HTTP/1.1 201 Created
Location: /api/orders/1001
Content-Type: application/json
 
{"id": 1001, "status": "pending"}

02Մեթոդները և նրանց խոստումները

GET-ը կարդում է ռեսուրսը և ոչինչ չպետք է փոխի։ HEAD-ը GET է առանց body-ի, օգտակար է ստուգումների համար։ POST-ը ինչ-որ բան ստեղծում է կամ գործողություն է գործարկում։ PUT-ը ռեսուրսն ամբողջությամբ փոխարինում է, PATCH-ը փոխում է դրա մի մասը, DELETE-ը ջնջում է այն։ OPTIONS-ը հարցնում է, թե ինչ է թույլատրված, և օգտագործվում է CORS preflight-երում։ Երկու հատկություն կարևոր է։ Safe մեթոդները (GET, HEAD, OPTIONS) վիճակ չեն փոխում, ուստի crawler-ները և prefetcher-ները կարող են ազատ կանչել դրանք։ Idempotent մեթոդները (GET, HEAD, PUT, DELETE, OPTIONS) կրկնվելիս նույն արդյունքն են տալիս, ուստի client-ները կարող են timeout-ից հետո կրկնել դրանք։ POST-ն ու PATCH-ը լռելյայն idempotent չեն․ POST-ի կրկնությունը կարող է երկու պատվեր ստեղծել, եթե սերվերը չի օգտագործում idempotency key։

  • Երբեք տվյալներ մի փոխեք GET-ով․ link preview-ն կամ prefetch-ը կարող է այն գործարկել։
  • Ավտոմատ կրկնեք միայն idempotent հարցումները։
  • Չաջակցվող մեթոդների համար օգտագործեք 405 Method Not Allowed՝ Allow header-ով։

03Status code-երի ընտանիքները

Առաջին թվանշանը պատմում է ամբողջ պատմությունը։ 1xx՝ տեղեկատվական (103 Early Hints-ը թույլ է տալիս սերվերին preload ակնարկներ ուղարկել իրական պատասխանից առաջ)։ 2xx՝ հաջողություն՝ 200 OK, 201 Created, 204 No Content։ 3xx՝ վերաուղղորդում՝ 301 և 308 մշտական, 302 և 307 ժամանակավոր (307-ն ու 308-ը պահպանում են մեթոդը և body-ն), 304 Not Modified՝ քեշավորման համար։ 4xx՝ client-ի սխալներ՝ 400 Bad Request, 401 Unauthorized (նույնականացված չէ), 403 Forbidden (նույնականացված է, բայց թույլատրված չէ), 404 Not Found, 405, 409 Conflict, 410 Gone, 413 Payload Too Large, 415 Unsupported Media Type, 422 Unprocessable Content (վալիդացիա), 429 Too Many Requests։ 5xx՝ սերվերի սխալներ՝ 500 Internal Server Error, 502 Bad Gateway, 503 Service Unavailable, 504 Gateway Timeout։ Ճիշտ կոդերը թույլ են տալիս client-ներին, քեշերին, մոնիտորինգին և որոնողական համակարգերին ճիշտ վարվել՝ առանց body-ն կարդալու։

04Header-ներ և cookie-ներ

Header-ները կրում են մետատվյալներ։ Հարցման՝ Host, Accept, Accept-Language, Authorization, Content-Type, User-Agent, Cookie։ Պատասխանի՝ Content-Type, Content-Length, Location, Set-Cookie, Cache-Control և անվտանգության header-ներ, ինչպիսիք են Strict-Transport-Security, Content-Security-Policy, X-Content-Type-Options: nosniff և Referrer-Policy։ Cookie-ները փոքր արժեքներ են, որոնք սերվերը խնդրում է բրաուզերին պահել և հետ ուղարկել այդ կայքին ուղղված յուրաքանչյուր հարցման հետ։ Flag-երն են որոշում, թե որքան անվտանգ են դրանք։ Secure՝ ուղարկվում է միայն HTTPS-ով։ HttpOnly՝ JavaScript-ը չի կարող այն կարդալ, ինչը սահմանափակում է XSS-ի վնասը։ SameSite=Lax-ը (բրաուզերի լռելյայնը) արգելափակում է ուղարկումը cross-site հարցումների մեծ մասում, Strict-ը արգելափակում է բոլորը, None-ը թույլ է տալիս cross-site, բայց պահանջում է Secure։ Path-ը, Domain-ը և Max-Age-ը կառավարում են տիրույթն ու կյանքի տևողությունը։ __Host- նախածանցը պարտադրում է Secure, Path=/ և Domain-ի բացակայություն։

http
HTTP/1.1 200 OK
Set-Cookie: __Host-session=abc123; Path=/; Secure; HttpOnly; SameSite=Lax; Max-Age=7200
Strict-Transport-Security: max-age=31536000; includeSubDomains
X-Content-Type-Options: nosniff
Referrer-Policy: strict-origin-when-cross-origin
Content-Security-Policy: default-src 'self'; img-src 'self' data:

05Քեշավորում՝ Cache-Control, ETag, 304

Քեշավորումը խնայում է աշխատանքը։ Cache-Control-ը բրաուզերներին և CDN-ներին ասում է՝ ինչ անել․ max-age=31536000, immutable՝ տարբերակավորված ռեսուրսների համար, ինչպիսին է app.3f9a1c.js-ը, no-cache՝ HTML-ի համար, որը կարելի է պահել, բայց ամեն անգամ պետք է revalidate անել, no-store՝ զգայուն տվյալների համար, որոնք երբեք չպետք է պահվեն, private՝ պատասխանների համար, որոնք նախատեսված են միայն մեկ օգտատիրոջ բրաուզերի համար, s-maxage՝ ընդհանուր քեշերի, օրինակ՝ CDN-ների համար, stale-while-revalidate՝ մի փոքր հին պատճենը մատուցելու համար, մինչ ֆոնում թարմացվում է։ Validator-ները revalidation-ը դարձնում են էժան․ սերվերն ուղարկում է ETag (մատնահետք) կամ Last-Modified, բրաուզերը հետո ուղարկում է If-None-Match կամ If-Modified-Since, և եթե ոչինչ չի փոխվել, սերվերը պատասխանում է 304 Not Modified՝ առանց body-ի։ Vary-ն քեշերին ասում է, թե որ հարցման header-ներն են փոխում պատասխանը, օրինակ՝ Accept-Encoding-ը։

http
GET /app.css HTTP/1.1
Host: example.com
If-None-Match: "a1b2c3"
 
HTTP/1.1 304 Not Modified
ETag: "a1b2c3"
Cache-Control: no-cache

06CORS առանց շփոթության

Բրաուզերները կիրառում են same-origin policy․ https://app.example.com-ի էջը չի կարող կարդալ https://api.example.com-ի պատասխանները, եթե API-ն դա թույլ չի տալիս։ CORS-ը (Cross-Origin Resource Sharing) այն եղանակն է, որով սերվերը պատասխանի header-ներով տալիս է այդ թույլտվությունը։ Պարզ հարցումներին պետք է միայն Access-Control-Allow-Origin։ JSON body-ով, Authorization-ի նման custom header-ներով կամ PUT-ի և DELETE-ի նման մեթոդներով հարցումները գործարկում են preflight․ բրաուզերը նախ ուղարկում է OPTIONS՝ հարցնելով, թե արդյոք իրական հարցումը թույլատրված է։ Եթե cookie-ներ են ներգրավված, սերվերը պետք է վերադարձնի ճշգրիտ origin-ը (ոչ թե *) և Access-Control-Allow-Credentials: true։ CORS-ը կիրառվում է միայն բրաուզերների կողմից․ այն ձեր API-ն չի պաշտպանում curl-ից կամ այլ սերվերներից, ուստի նույնականացումը դեռ պետք է։

http
OPTIONS /api/orders HTTP/1.1
Origin: https://app.example.com
Access-Control-Request-Method: POST
Access-Control-Request-Headers: content-type, authorization
 
HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://app.example.com
Access-Control-Allow-Methods: GET, POST, PATCH, DELETE
Access-Control-Allow-Headers: content-type, authorization
Access-Control-Allow-Credentials: true
Access-Control-Max-Age: 600
Vary: Origin

07HTTP-ի ուսումնասիրությունը գործնականում

Բրաուզերի Network tab-ը ցույց է տալիս յուրաքանչյուր հարցում՝ header-ներով, ժամանակներով, cookie-ներով և պատասխանով։ Աջ սեղմեք հարցման վրա և ընտրեք Copy as cURL՝ այն տերմինալում վերարտադրելու համար։ curl -v-ն տպում է ամբողջ փոխանակումը, -I-ն բերում է միայն header-ները։ API-ների համար օգնում են Postman-ը, Insomnia-ն կամ HTTPie-ն, բայց runbook-ում պարզ curl-ն ամենաշարժականն է։ Debug անելիս կողք կողքի համեմատեք աշխատող և չաշխատող հարցումները․ սովորաբար մեկ header-ը, cookie-ն կամ status code-ն է բացատրում տարբերությունը։ Չմոռանաք հեռացնել token-ներն ու cookie-ները՝ նախքան պատճենված հարցումը որևէ մեկի հետ կիսվելը։

bash
curl -sI https://example.com/                      # headers only
curl -v https://api.example.com/health             # full exchange
curl -s -X POST https://api.example.com/orders \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $TOKEN" \
  -d '{"productId":42,"quantity":2}' -w "\n%{http_code}\n"

Օգտագործեք, երբ

  • Ցանկացած API կամ վեբ endpoint նախագծելիս։
  • Login-ի, session-ի, քեշավորման կամ cross-origin խնդիրները debug անելիս։
  • Production կայքի համար անվտանգության header-ներ և cookie-ների flag-եր կարգավորելիս։
  • Երրորդ կողմի ծառայությունների և webhook-ների հետ ինտեգրվելիս։

Մի՛ օգտագործեք, երբ

  • Անընդհատ real-time թարմացումների համար պարզ request–response-ը վատնող է․ օգտագործեք WebSockets կամ Server-Sent Events։
  • Խիստ սխեմաներով, բարձր թողունակությամբ ներքին ծառայությունների կանչերի համար gRPC-ն կարող է ավելի հարմար լինել։

Այլընտրանքներ

  • WebSockets

    Երկկողմանի մշտական կապ՝ չատի, live պատվերների և dashboard-ների համար։

  • Server-Sent Events

    Միակողմանի հոսք սերվերից բրաուզեր՝ պարզ HTTP-ով։

  • gRPC

    Բինար RPC HTTP/2-ի վրա՝ գեներացված client-ներով, տարածված ծառայությունների միջև։

Լավագույն պրակտիկաներ

  1. Օգտագործեք այն մեթոդն ու status code-ը, որոնք համապատասխանում են իրականում կատարվածին։
  2. Session cookie-ները սահմանեք Secure, HttpOnly և SameSite=Lax (կամ Strict) flag-երով։
  3. Տարբերակավորված ռեսուրսները քեշավորեք մեկ տարով՝ immutable-ով, HTML-ը revalidate արեք։
  4. Անձնական կամ վճարային տվյալներ պարունակող պատասխանների համար օգտագործեք no-store։
  5. CORS-ում թույլատրեք միայն հայտնի origin-ներ․ երբեք մի արտացոլեք ցանկացած origin credentials-ի հետ միասին։
  6. Ուղարկեք HSTS, nosniff, Referrer-Policy և Content-Security-Policy։

Տարածված սխալներ

  • Վերադարձնել 200՝ body-ում սխալի հաղորդագրությամբ, կոտրելով client-ներն ու մոնիտորինգը։
  • Շփոթել 401-ն ու 403-ը։
  • Օգտագործել Access-Control-Allow-Origin: * և սպասել, որ cookie-ները կաշխատեն, կամ արտացոլել ցանկացած origin credentials-ով։
  • Տվյալներ փոխել GET հարցումներով։
  • Օգտատիրոջը հատուկ պատասխանները հանրայնորեն քեշավորել CDN-ում։

Խորը վերլուծություն

08Message framing և request smuggling

HTTP/1.1-ում ստացողը պետք է իմանա, թե որտեղ է ավարտվում body-ն։ Content-Length-ը տալիս է չափը բայթերով, Transfer-Encoding: chunked-ը body-ն ուղարկում է կտորներով՝ յուրաքանչյուրն իր երկարությամբ, և ավարտվում է զրո չափի chunk-ով։ Եթե հարցումը պարունակում է երկուսն էլ, կամ դրանցից մեկի սխալ ձևաչափված տարբերակը, առջևի proxy-ն և back-end սերվերը կարող են չհամաձայնել, թե որտեղ է ավարտվում հարցումը։ Այդ դեպքում հարձակվողը կարող է առաջին հարցման body-ի մեջ թաքցնել երկրորդ հարցումը, որը back end-ը կընդունի որպես հաջորդ օգտատիրոջ հարցման սկիզբ։ Սա HTTP request smuggling է, և այն կարող է շրջանցել անվտանգության կանոնները կամ «թունավորել» քեշը։ Պաշտպանություն. proxy-ները և սերվերները թարմ պահեք, մերժեք երկու header-ով կամ անվավեր framing-ով հարցումները, հնարավորության դեպքում նախընտրեք HTTP/2 ամբողջ ճանապարհին և խուսափեք ձեռքով գրված proxy-ներից։ HTTP/2-ը և HTTP/3-ը ունեն իրենց սեփական framing-ը, բայց proxy-ում HTTP/1.1-ի downgrade-ը ռիսկը վերադարձնում է։

09Conditional request-ներ՝ ապահով միաժամանակյա թարմացումների համար

Երկու ադմին բացում են նույն ապրանքը, երկուսն էլ խմբագրում են, և երկրորդի պահպանումը լուռ վերագրում է առաջինին. սա lost update խնդիրն է։ HTTP-ն այն լուծում է validator-ներով։ GET պատասխանը ներառում է ETag (տարբերակի fingerprint)։ Client-ը փոփոխությունն ուղարկում է If-Match-ով՝ սահմանված այդ ETag-ին։ Եթե ռեսուրսն այդ ընթացքում փոխվել է, սերվերը մերժում է 412 Precondition Failed-ով, և client-ը վերաբեռնում ու միավորում է փոփոխությունները։ PUT-ի վրա If-None-Match: *-ը նշանակում է՝ ստեղծել միայն եթե գոյություն չունի, ինչը կանխում է պատահական վերագրումները։ Սերվերները կարող են գրառումների վրա պարտադրել precondition-ներ 428 Precondition Required-ով։ Ներսում սա հարմար համընկնում է version սյունակին կամ updated_at ստուգմանը մեկ UPDATE ... WHERE version = ? հրամանում, այնպես որ ստուգումը և գրառումը ատոմար են։

http
GET /api/products/42 HTTP/1.1
 
HTTP/1.1 200 OK
ETag: "v7"
 
PATCH /api/products/42 HTTP/1.1
If-Match: "v7"
Content-Type: application/json
 
{"price": 4900}
 
HTTP/1.1 412 Precondition Failed      # someone saved v8 first

10Content negotiation, Vary և range request-ներ

Մեկ URL-ը կարող է ունենալ մի քանի ներկայացում։ Client-ը նախընտրությունները նշում է Accept, Accept-Language և Accept-Encoding header-ներով, իսկ սերվերն ընտրում է մեկը՝ իդեալում պատասխանելով 406, երբ ոչինչ չի համապատասխանում։ Ցանկացած header, որը փոխում է պատասխանը, պետք է նշված լինի Vary-ում, այլապես քեշը կարող է Brotli body մատուցել client-ին, որն ընդունում է միայն gzip, կամ ռուսերեն էջ՝ անգլիախոս այցելուին։ Vary-ն նաև բաժանում է քեշը. Vary: User-Agent-ը կամ Vary: Cookie-ն կարող են քեշավորումը գրեթե անօգուտ դարձնել, ուստի լեզուների համար նախընտրեք առանձին URL-ներ, իսկ Vary-ն հնարավորության դեպքում սահմանափակեք Accept-Encoding-ով։ Range request-ները թույլ են տալիս client-ին խնդրել ֆայլի մի մասը Range: bytes=0-1023-ով. սերվերը պատասխանում է 206 Partial Content և աջակցությունը հայտարարում է Accept-Ranges: bytes-ով։ Video player-ները և download manager-ները սրանից են կախված seek-ի և ընդհատված ներբեռնումը շարունակելու համար։

bash
curl -s -o /dev/null -D - -H "Range: bytes=0-1023" https://example.com/video.mp4
# HTTP/2 206
# content-range: bytes 0-1023/48213004
# accept-ranges: bytes

11Cookie-ներ կայքերի, subdomain-ների և frame-երի միջև

Site-ը և origin-ը տարբեր գաղափարներ են։ Origin-ը scheme + host + port է, site-ը registrable domain-ն է, ուստի app.example.com-ը և api.example.com-ը տարբեր origin-ներ են, բայց նույն site-ը։ SameSite կանոններն օգտագործում են site-երը, ահա թե ինչու SameSite=Lax cookie-ն դեռ ուղարկվում է ձեր subdomain-ների միջև։ Cross-site դեպքում Lax cookie-ները գնում են միայն top-level GET նավիգացիաների հետ, երբեք՝ այլ կայքից fetch-ի կամ form POST-ի հետ։ Domain attribute-ով սահմանված cookie-ները կիսվում են բոլոր subdomain-ների հետ, ներառյալ third-party ծառայության կողմից աշխատեցվողները, ուստի session cookie-ները պահեք host-only։ Third-party կոնտեքստները սահմանափակված են. Safari-ն և Firefox-ը լռելյայն արգելափակում են third-party cookie-ները, իսկ Partitioned cookie-ները (CHIPS) թույլ են տալիս ներդրված widget-ին վիճակը պահել առանձին՝ յուրաքանչյուր top-level site-ի համար։ Բրաուզերները նաև սահմանափակում են cookie-ի չափը՝ մոտ 4 KB յուրաքանչյուրը, և ամեն cookie ուղարկվում է ամեն հարցման հետ, ուստի մեծ cookie-ները bandwidth են ծախսում։

http
Set-Cookie: __Host-sid=8f2c...; Path=/; Secure; HttpOnly; SameSite=Lax
Set-Cookie: widget_state=abc; Path=/; Secure; SameSite=None; Partitioned

Իրական իրավիճակներ

01

Login-ը աշխատում է desktop-ում, բայց ոչ ներդրված iframe-ի ներսում

Խնդիր

Ամրագրման widget-ն աշխատում է iframe-ում գործընկերների կայքերում։ Օգտատերերը կարող են login անել հիմնական կայքում, բայց widget-ի ներսում session-ն անհետանում է յուրաքանչյուր հարցումից հետո։

Ինչպես լուծել

Այդ կոնտեքստում session cookie-ն third-party cookie է, ուստի SameSite=Lax-ը արգելափակում է այն, իսկ որոշ բրաուզերներ ամբողջությամբ են արգելափակում։ Տարբերակներ. widget-ի cookie-ն սահմանեք SameSite=None; Secure; Partitioned-ով, որպեսզի աշխատի յուրաքանչյուր գործընկեր կայքի համար առանձին, կամ widget-ում խուսափեք cookie-ներից և օգտագործեք կարճակյաց token՝ փոխանցված postMessage-ով և ուղարկված Authorization header-ով։ Հիմնական կայքի session cookie-ն մի թուլացրեք մինչև SameSite=None, ինչը նորից բացում է CSRF ռիսկը։ Թեստավորեք Safari-ում և Firefox-ում, որոնք լռելյայն ամենախիստն են։

02

Հաճախորդները քեշից սխալ լեզու են տեսնում

Խնդիր

Կայքը լեզուն որոշում է Accept-Language-ից և նույն URL-ով մատուցում է ռուսերեն կամ անգլերեն։ CDN ավելացնելուց հետո այցելուները երբեմն սխալ լեզու են ստանում։

Ինչպես լուծել

Պատասխանը կախված է header-ից, որի մասին քեշը չգիտի։ Հուսալի լուծումը յուրաքանչյուր լեզվի համար առանձին URL-ներն են, օրինակ՝ /en/ և /ru/, root-ից մեկանգամյա redirect-ով՝ հիմնված Accept-Language-ի կամ պահպանված նախընտրության վրա, և hreflang tag-երով որոնողական համակարգերի համար։ Redirect-ը ինքը նշեք private կամ Vary: Accept-Language, որպեսզի այն չկիսվի։ Յուրաքանչյուր էջին Vary: Accept-Language ավելացնելը հնարավոր է, բայց քեշը մասնատում է բազմաթիվ տարբերակների, և որոշ CDN-ներ այն անտեսում են։ Փոփոխությունից հետո purge արեք և ստուգեք curl-ով՝ տարբեր Accept-Language արժեքներով։

03

Երկու աշխատակից վերագրում են միմյանց խմբագրումները

Խնդիր

Ադմին պանելում մենյուի գները երբեմն հետ են վերադառնում։ Log-երը ցույց են տալիս երկու PATCH հարցում՝ մեկ րոպե տարբերությամբ, տարբեր օգտատերերից, որոնք խմբագրում են նույն տարրը։

Ինչպես լուծել

Ավելացրեք optimistic concurrency։ Յուրաքանչյուր GET-ի հետ վերադարձրեք ETag կամ version համար։ PATCH-ի և PUT-ի վրա պահանջեք If-Match և update-ն իրականացրեք որպես UPDATE ... WHERE id = ? AND version = ?՝ ավելացնելով version-ը։ Եթե ոչ մի տող չի փոխվել, վերադարձրեք 412 Precondition Failed՝ ընթացիկ version-ով։ Այդ դեպքում ադմին UI-ն ցույց է տալիս «այս տարրը փոխվել է ուրիշի կողմից» և առաջարկում վերաբեռնել։ Վերադարձրեք 428, եթե client-ը մոռանում է header-ը, որպեսզի հին client-ները չկարողանան լուռ շրջանցել ստուգումը։

Արագ ուղեցույց

Ցույց տալ միայն պատասխանի header-ները
curl -sI https://example.com/
Ցույց տալ հարցման և պատասխանի header-ները
curl -sv -o /dev/null https://example.com/ 2>&1 | grep -E "^[<>]"
Թեստավորել conditional GET
curl -sI -H 'If-None-Match: "a1b2c3"' https://example.com/app.css
Թեստավորել CORS preflight
curl -si -X OPTIONS https://api.example.com/orders -H "Origin: https://app.example.com" -H "Access-Control-Request-Method: POST"
Ներբեռնել ֆայլի մի մասը
curl -s -r 0-1023 -o part.bin https://example.com/file.zip
Հետևել redirect-ներին և տպել յուրաքանչյուր քայլը
curl -sIL https://example.com/old-page | grep -iE "^HTTP|^location"
Ապահով session cookie
Set-Cookie: __Host-sid=...; Path=/; Secure; HttpOnly; SameSite=Lax
Երկարակյաց տարբերակված ֆայլ
Cache-Control: public, max-age=31536000, immutable
Երբեք չպահել
Cache-Control: no-store

Իմ իրական նախագծերում

  • Իմ Laravel և NestJS բեքենդները HTTP/JSON-ով սպասարկում են վեբ ֆրոնտենդներ, ադմին պանելներ և React Native հավելվածներ, իսկ վեբ և մոբայլ ալիքները կիսում են հիմնական լոգիկան։
  • Pet-store հավելվածում HTTP client-ը կրկնում է միայն idempotent մեթոդները, այնպես որ timeout-ը երբեք կրկնակի պատվեր չի ստեղծում։
  • Next.js կայքերը, որոնց վրա աշխատել եմ, օգտագործում են custom server՝ անվտանգության և քեշի header-ներով։

Հարցեր և պատասխաններ

Q1Ո՞րն է տարբերությունը 401-ի և 403-ի միջև։

401 Unauthorized-ն իրականում նշանակում է «նույնականացված չէ»․ սերվերը չգիտի, թե ով եք, որովհետև token-ը կամ session-ը բացակայում է, ժամկետանց է կամ անվավեր։ Client-ը պետք է login անի կամ թարմացնի credentials-ը, և HTTP auth սխեմաների համար պատասխանը պետք է ներառի WWW-Authenticate header։ 403 Forbidden-ը նշանակում է, որ սերվերը գիտի, թե ով եք, բայց ձեզ թույլատրված չէ դա անել, օրինակ՝ գանձապահը փորձում է բացել ֆինանսական հաշվետվությունները։ Կրկին login անելը չի օգնի։ Այն ռեսուրսների համար, որոնց գոյության մասին օգտատերը նույնիսկ չպետք է իմանա, օրինակ՝ մեկ այլ tenant-ի տվյալները, 404 վերադարձնելը հաճախ ավելի լավ է, քան 403-ը, որովհետև այն չի բացահայտում գոյությունը։

Q2HTTP-ի ո՞ր մեթոդներն են idempotent, և ինչո՞ւ է դա կարևոր։

GET, HEAD, OPTIONS, PUT և DELETE մեթոդները idempotent են․ նույն հարցումը երկու անգամ ուղարկելը սերվերը թողնում է նույն վիճակում, ինչ մեկ անգամ ուղարկելը։ GET-ը, HEAD-ը և OPTIONS-ը նաև safe են, այսինքն՝ ոչինչ չպետք է փոխեն։ POST-ն ու PATCH-ը լռելյայն idempotent չեն։ Դա կարևոր է կրկնությունների համար․ ցանցերը խափանվում են, և պատասխան չստացած client-ը չգիտի՝ սերվերը մշակե՞լ է հարցումը, թե ոչ։ Idempotent հարցումները կարելի է ավտոմատ կրկնել։ Վճարումների կամ պատվերների նման POST-երի համար ավելացնում եմ Idempotency-Key header, որպեսզի սերվերը կարողանա վերադարձնել սկզբնական արդյունքը՝ կրկնօրինակ ստեղծելու փոխարեն։

Q3Ինչպե՞ս է բրաուզերի քեշավորումն աշխատում ETag-ի և Cache-Control-ի հետ։

Cache-Control-ը որոշում է՝ արդյոք և որքան ժամանակ կարելի է պատասխանը վերաօգտագործել։ max-age-ով բրաուզերն օգտագործում է իր պատճենը՝ առանց հարցնելու, մինչև ժամկետը լրանա։ no-cache-ով այն պահում է պատճենը, բայց օգտագործելուց առաջ պետք է revalidate անի։ Revalidation-ն օգտագործում է validator-ներ․ սերվերն ուղարկել է ETag, ուստի բրաուզերը հարցնում է If-None-Match-ով, և եթե ռեսուրսը չի փոխվել, սերվերը վերադարձնում է 304 Not Modified՝ առանց body-ի՝ խնայելով bandwidth-ն ու աշխատանքը։ Իմ սովորական կարգավորումն է՝ երկար max-age immutable-ով hash-ով ռեսուրսների համար, no-cache ETag-ով HTML-ի համար, և no-store մասնավոր տվյալների համար, ինչպիսիք են հաշվի կամ վճարման էջերը։

Q4Ի՞նչ է CORS-ը, և ինչո՞ւ է իմ հարցումը ձախողվում միայն բրաուզերում։

CORS-ը բրաուզերի անվտանգության մեխանիզմ է։ Լռելյայն մի origin-ի սկրիպտը չի կարող կարդալ մեկ այլ origin-ի պատասխանները։ Սերվերը կարող է դա թույլ տալ՝ վերադարձնելով Access-Control-Allow-Origin և հարակից header-ներ։ Ոչ պարզ հարցումների համար, օրինակ՝ JSON body-ով կամ Authorization header-ով, բրաուզերը նախ ուղարկում է preflight OPTIONS հարցում, և եթե սերվերը ճիշտ չի պատասխանում, իրական հարցումը երբեք չի կատարվում։ curl-ն ու Postman-ը CORS չեն կիրառում, ահա թե ինչու նույն կանչն այնտեղ աշխատում է։ Լուծումը սերվերի կողմում է՝ թույլատրել ֆրոնտենդի ճշգրիտ origin-ը, անհրաժեշտ մեթոդներն ու header-ները, և credentials, եթե cookie-ներ են օգտագործվում։

Q5Ինչպե՞ս դարձնել cookie-ներն անվտանգ։

Սահմանեք Secure, որպեսզի cookie-ն ուղարկվի միայն HTTPS-ով, HttpOnly, որպեսզի JavaScript-ը չկարողանա այն կարդալ, և XSS բագը չկարողանա գողանալ session-ը, և SameSite=Lax կամ Strict, որպեսզի բրաուզերը այն չկցի cross-site հարցումների մեծ մասին, ինչը նվազեցնում է CSRF-ը։ Տիրույթը պահեք նեղ․ խուսափեք Domain ատրիբուտից, եթե subdomain-ներին այն պետք չէ, և դիտարկեք __Host- նախածանցը, որը պարտադրում է Secure, Path=/ և Domain-ի բացակայություն։ Կյանքի տևողությունը պահեք կարճ, login-ի ժամանակ փոխեք session ID-ն և պահեք միայն անթափանց նույնացուցիչ, երբեք՝ անձնական տվյալներ։ Վիճակ փոխող ֆորմերի համար դեռ օգտագործում եմ CSRF token-ներ՝ որպես defense in depth։

Q6Ո՞րն է տարբերությունը 301-ի, 302-ի, 307-ի և 308-ի միջև։

301-ն ու 308-ը մշտական redirect-ներ են․ բրաուզերներն ու որոնողական համակարգերը հիշում են դրանք և վարկանիշը փոխանցում նոր URL-ին։ 302-ն ու 307-ը ժամանակավոր են․ սկզբնական URL-ը մնում է canonical-ը։ Յուրաքանչյուր զույգի ներսում տարբերությունը մեթոդն է։ 301-ի և 302-ի դեպքում բրաուզերները պատմականորեն POST-ը նոր URL-ի վրա փոխում են GET-ի։ 307-ն ու 308-ը երաշխավորում են, որ մեթոդն ու body-ն պահպանվում են։ Այնպես որ էջերը մշտապես տեղափոխելու համար, օրինակ՝ HTTP-ից HTTPS կամ հին slug-ից նորը, օգտագործում եմ 301 կամ 308, POST ընդունող API endpoint-ների համար՝ 307 կամ 308, կարճաժամկետ տեղափոխությունների համար՝ 302 կամ 307։

Սենիոր մակարդակի հարցեր

S1Ինչպե՞ս եք ընտրում cookie-ների և bearer token-ների միջև web հավելվածի և մոբայլ հավելվածի համար։

Բրաուզերի համար նախընտրում եմ HttpOnly, Secure, SameSite session cookie՝ հավելվածի հետ նույն site-ում. JavaScript-ը չի կարող այն գողանալ XSS-ով, բրաուզերն ինքն է այն ուղարկում, իսկ server-side session-ները հեշտ է revoke անել։ Գինը CSRF-ն է, որը լուծվում է SameSite-ով և CSRF token-ներով։ Մոբայլ հավելվածների համար cookie-ները անհարմար են, ուստի օգտագործում եմ կարճակյաց access token-ներ refresh token-ներով, որոնք պահվում են պլատֆորմի secure storage-ում։ Երկարակյաց token-ները բրաուզերի localStorage-ում պահելը այն տարբերակն է, որից խուսափում եմ, քանի որ ցանկացած XSS կարող է դրանք կարդալ։ Շատ backend-ներ աջակցում են երկուսին էլ. նույն auth ծառայությունը թողարկում է session-ներ web-ի համար և token-ներ մոբայլի համար։ JWT-ն օգնում է, երբ այլ ծառայություններ պետք է ստուգեն ինքնությունը առանց lookup-ի, բայց revocation-ը դժվարանում է, ուստի կյանքի տևողությունը պետք է կարճ մնա։

S2Որո՞նք են բիզնես կանոնները HTTP caching-ի մեջ դնելու առավելություններն ու թերությունները։

HTTP caching-ը չափազանց արդյունավետ է, քանի որ բրաուզերները, CDN-ները և proxy-ները բոլորը հասկանում են այն, և այն կոդ չի պահանջում։ Բայց այն ձեր ճշտության մի մասը տեղափոխում է header-ների մեջ, որոնք շատ շերտեր մի փոքր տարբեր են մեկնաբանում։ Սխալները լուրջ են. private պատասխանը պահող հրապարակային քեշը տվյալների արտահոսք է, իսկ HTML-ի վրա երկար max-age-ը նշանակում է, որ օգտատերերը չեն ստանա ուղղումը, մինչև ժամկետը չանցնի։ Կանոնները պահում եմ պարզ. immutable՝ hash-ով ֆայլերի համար, կարճ s-maxage գումարած stale-while-revalidate՝ հրապարակային HTML-ի համար, private կամ no-store՝ օգտատիրոջն առնչվող ամեն ինչի համար, և purge-եր՝ deploy-ներով կամ բովանդակության իրադարձություններով։ Նաև գրում եմ թեստեր, որոնք ստուգում են header-ները հիմնական route-երում, քանի որ header-ների regression-ները սովորական ֆունկցիոնալ թեստավորման ժամանակ չեն երևում։

S3Ինչպե՞ս կպաշտպանեք API-ն CSRF-ից, եթե այն օգտագործում է cookie-ներ։

Նախ՝ օգտագործեք SameSite=Lax կամ Strict session cookie-ներ, որոնք թույլ չեն տալիս բրաուզերներին դրանք ուղարկել cross-site POST, PUT և DELETE հարցումներով և այլ կայքերից fetch կանչերով։ Երկրորդ՝ երբեք վիճակ մի փոխեք GET-ով, քանի որ Lax-ը դեռ թույլ է տալիս top-level GET նավիգացիաներ։ Երրորդ՝ ավելացրեք պաշտպանություն, որը կախված չէ բրաուզերի վարքագծից. synchronizer token form-երում, կամ double-submit token, ուղարկված custom header-ով, օրինակ՝ X-CSRF-Token, որը այլ կայքերը չեն կարող սահմանել առանց CORS-ն անցնելու։ Origin կամ Sec-Fetch-Site header-ները allowlist-ի հետ ստուգելը էժան լրացուցիչ շերտ է։ CORS-ը չպետք է credentials-ով արտացոլի կամայական origin-ներ, այլապես ամբողջ սխեման փլուզվում է։ Մաքուր bearer-token API-ները խոցելի չեն CSRF-ի նկատմամբ, բայց ռիսկը տեղափոխում են token-ների պահպանման վրա։

Բառարան

Origin
Scheme-ը, host-ը և port-ը միասին, օրինակ՝ https://app.example.com:443. same-origin policy-ի միավորը։
Site
Registrable domain-ը, օրինակ՝ example.com. նրա subdomain-ները same-site են։ SameSite cookie-ները օգտագործում են այս գաղափարը։
Idempotent
Հարցումը կրկնելը սերվերի վրա նույն ազդեցությունն ունի, ինչ մեկ անգամ ուղարկելը։
ETag
Պատասխանի տարբերակի նույնացուցիչ, որն օգտագործվում է քեշի revalidation-ի և lost update-ները կանխելու համար։
Preflight
OPTIONS հարցում, որը բրաուզերն ուղարկում է որոշ cross-origin հարցումներից առաջ՝ թույլտվություն խնդրելու համար։
Vary
Պատասխանի header, որը թվարկում է պատասխանը փոխող request header-ները, որպեսզի քեշերը պահեն առանձին տարբերակներ։
Chunked encoding
HTTP/1.1-ի եղանակ՝ body-ն կտորներով ուղարկելու համար, երբ ընդհանուր չափը նախապես հայտնի չէ։
Request smuggling
Հարձակում, որտեղ proxy-ն և սերվերը չեն համաձայնում հարցման սահմանների շուրջ, և թաքնված հարցումը սողոսկում է ներս։
206 Partial Content
Range հարցման պատասխանը, որը պարունակում է ֆայլի միայն պահանջված բայթերը։
CHIPS
Cookies Having Independent Partitioned State. Partitioned նշված cookie-ներ, որոնք պահվում են առանձին յուրաքանչյուր top-level site-ի համար։

Պրոդուկտի գաղափար ունե՞ք։Եկեք ստեղծենք այն։

Պատմեք ձեր գաղափարի, պրոդուկտի կամ թիմի մասին։ Սովորաբար պատասխանում եմ մեկ աշխատանքային օրվա ընթացքում։