2重リクエスト完全攻略HANDBOOK / Double Request Handbook
by
ShoheiMitani
×
Copy
Open
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Slide 1
Slide 1 text
2ॏϦΫΤετશ߈ུHANDBOOK Shohei Mitani @ εϚʔτόϯΫ
Slide 2
Slide 2 text
2ॏϦΫΤετ • ޡͬͯෳճಉ͡ϦΫΤετ͕ૹΒΕɺॏෳͯ͠ॲཧ͕ߦΘΕͯ͠·͏͜ͱ • αϒϛοτϘλϯ͕2ճԡ͞Εͨ • ొը໘͕Ϧϩʔυ͞Εͨ • ֎෦αʔϏε͔Βෳճಉ͡σʔλ͕ૹΒΕͨ • όον͕2ճ࣮ߦ͞Εͨ • 2ॏαϒϛοτͱ͍͏ݴ͍ํ͋Δ͕ɺWebϒϥβҎ֎ʹى͜Γ͏Δ Λѻ͍͍ͨͷͰ2ॏϦΫΤετͱݺͿ • 2ճҎ্ϦΫΤετ͢ΔଟॏϦΫΤετ2ॏϦΫΤετͱݺͿ͜ͱʹ͢Δ
Slide 3
Slide 3 text
͠2ॏϦΫΤετ͕ൃੜͨ͠Β…?? • ܝࣔ൘ʹಉ͡༰͕2ճߘ͞ΕΔ... • ಉ͕͡2ճߪೖ͞Εͯɺ2ॏͰߴ͕ݮΔ͜ͱʹ… • ܾࡁ / ૹۚ / ༧ / ग़ / ථ / ใु༩ / ਃ / etc… • ѱ༻͞Εͯෆਖ਼߈ܸΛड͚ΔηΩϡϦςΟϗʔϧʹ… • Etc…
Slide 4
Slide 4 text
2ॏϦΫΤετͷରࡦҙ֎ͱ͍͠ • ΫϥΠΞϯτͰ੍ޚ͢Ε͍͍Μ͡Όͳ͍ͷ͔ʁ • ΫϦοΫ࿈ଧ / ϖʔδ࠶ಡΈࠐΈ / Δˠ࠶ૹ৴ͳͲɺͲ͜·ͰରԠͰ͖Δʁ • ϒϥβͷσϕϩούʔπʔϧͰૢ࡞͞ΕͨΒʁ • ෳλϒʗෳ͔Βಉ࣌ʹૢ࡞͞Εͨ߹ʹͰ͖Δରࡦʁ • ֎෦αʔϏε͔Βͷࣗಈ࠶ૹͳͲɺΫϥΠΞϯτଆΛ੍ޚͰ͖ͳ͍߹ʹʁ • όοΫΤϯυͰςʔϒϧઃܭΛ্ख͘ΕେৎͰ͠ΐ • ϢχʔΫ੍͕͚ͭΒΕͳ͔ͬͨΓɺϩοΫ͕औΕͳ͍ঢ়گ͋Δ • ҙਤͨ͠ෳճͷૢ࡞ͱɺࣄނతʹൃੜͨ͠2ॏϦΫΤετΛผͰ͖Δʁ
Slide 5
Slide 5 text
Θ͟Θ͟Kaigi on RailsͰൃද͢Δ΄Ͳʁ • WebͰݕࡧͯ͠ग़ͯ͘Δํ๏WebϒϥβΛલఏͱ ͯ͠ͷ͕ଟ͍ • ʮJavaScritptͰʙʯʮ֬ೝμΠΞϩάग़ͯ͠ʙʯ • ʮઈରʹೋॏαϒϛοτΛڐ͞ͳ͍༑ͷձʯͷϒϩάΑ ͘·ͱ·ͬͯΔ • ݱ࣮ͷΞϓϦέʔγϣϯෳࡶͰ৭ʑͳέʔε͕͋Δ • ຖճɺରࡦΛௐͨΓಠࣗʹฤΈग़͢͜ͱʹർΕͨ • ͜Ε͚ͩݟ͓͚ͯେମΧόʔ͞ΕͯΔͷΛ࡞Γ͍ͨ https://qiita.com/unmelt/items/fb1eff5a2d9bc4da1f7e
Slide 6
Slide 6 text
ࠓͷൃදςʔϚ • ୭ʹͱͬͯۙͰॏཁͳ2ॏϦΫΤετʹ·ͳ͍͍ͯ͘ੈքΛ࡞Δ • 2ॏϦΫΤετͷͷཧղ • ༷ʑͳ2ॏϦΫΤετରࡦͷཧղ • ϢʔεέʔεʹԠͨ͡ϕετϓϥΫςΟεͷ୳ࡧ • ྩ7࣌ͰͷใΛ·ͱΊͨHANDBOOKΛఏڙ • ۀͰૺ۰ͨ࣌͠ʹݟฦͤΔࢿྉͱͳΕ͍ • ଞʹ͜͏͍͏ͷ͋ΔΑʂͬͯํ๏͋Εڭ͍͑ͯͩ͘͞🙌 • ݸʑͷରࡦͷৄࡉׂѪ͠·͢
Slide 7
Slide 7 text
ࣗݾհ ࡾ୩ ণฏ Έͨʹ ͠ΐ͏͍ εϚʔτόϯΫ Engineering Manager / Software Engineer • SIer → Fablic → ָఱ → εϚʔτόϯΫ • ΤϯδχΞྺ11ɺRailsྺ7 • Welcome Fintech Community ӡӦ
Slide 8
Slide 8 text
ৗͰ͍ͬͯΔαʔϏεͷཪଆΛެ։Մೳͳܗʹམͱ͠ࠐΜͰൃද͢Δͷ͕͖ builderscon 2024 YAPC::Hiroshima 2024 YAPC::Fukuoka 2025 eKYC Χʔυܾࡁ ڝഅ x ػցֶश χον͗ͯ͢ڵຯ࣋ͨΕͳ͍? ެ։͢Δͱڝ߹༏Ґੑࣦ͏? ڪΕͣൃද͢Δ͜ͱͰಘΒΕΔ͜ͱଟ͍
Slide 9
Slide 9 text
ࠓͬͪ͜ͷ Kaigi on Rails 2022 Kaigi on Rails 2021 Kaigi on Rails 2023 ։ൃݱͰͷ࣮ઓΛநԽɾ൚༻తֶͯ͠ͼʹม͍͑ͯ͘׆ಈ͖ ࢹ ঢ়ଶཧ ςʔϒϧఆٛมߋ
Slide 10
Slide 10 text
2ॏϦΫΤετͷޚࡦ
Slide 11
Slide 11 text
લఏ͢Γ߹Θͤʙհ͢Δޚࡦͷείʔϓʙ • POST / PUT / DELETEͷߋ৽ܥૢ࡞Λத৺ʹѻ͏ʢGETͷԠ༻Մʣ • ૹ৴ऀଆʹѱҙͳ͍͕ࣄނతʹ2ॏϦΫΤετ͕ൃੜ͢Δͷޚࡦ • αϒϛοτϘλϯ͕ԿԡͤΔͷ࣮࿙Ε • όοΫΤϯυͰͷλΠϜΞτʹΑΓɺΫϥΠΞϯτ͔Β࠶ૢ࡞͕Ͱ͖Δέʔε • ૹ৴ऀଆ͕ѱҙΛ࣋ͬͯ2ॏϦΫΤετΛߦ͏Α͏ͳͷޚࡦ • ੬ऑੑΛಥ͍ͨϦϓϨΠ߈ܸ / ෳͰͷಉ࣌ૢ࡞ • ༷ͱͯ͠ಉ͡༰ͷૢ࡞͕ڐ༰͞Ε͍ͯΔέʔεͱͷ۠ผ͢Δํ๏ • ಉҰͷߪೖ / ࿈ߘ
Slide 12
Slide 12 text
ෳͷޚͰߟ͑Δ 📱 🐟 ΫϥΠΞϯτଆ ޚࡦͷҹ όοΫΤϯυଆ ޚࡦͷҹ
Slide 13
Slide 13 text
ᶃ αϒϛοτϘλϯͷ੍ޚ ᶄ Post-Redirect-Get (PRG) ύλʔϯ ᶅ ഉଞ੍ޚ • Ϧιʔεͷ൵؍ϩοΫ • FIFOʹΑΔॱং੍ޚ • ΞυόΠβϦʔϩοΫ ᶆ ςʔϒϧઃܭ • ঢ়ଶભҠͷϧʔϧԽ • ϢχʔΫ੍ ࠓհ͢Δޚࡦͨͪ ᶇ ϨʔτϦϛοτ ᶈ APIΩϟογϡ ᶉ Idempotency-Keyϔομ ᶊ ETag ʴ If-Match ᶋ ϫϯλΠϜτʔΫϯ
Slide 14
Slide 14 text
ᶃ αϒϛοτϘλϯͷ੍ޚ • ࠷جຊతͰ࠷ॳʹΔͰ͋Δ2ॏϦΫΤετ Λ͙ํ๏ • ϘλϯΛԡͨ͠Βྃ͢Δ·Ͱඇ׆ੑԽ͢Δ • Βͳ͍ͱ͍͏બࢶͳͦ͞͏ʢ?ʣ • ॲཧঢ়ଶΛอ͓͖࣋ͯ͠ɺॲཧதʹૢ࡞͞Εͨ ߹ʹϝοηʔδΛදࣔ͢Δ͜ͱՄೳ 📱
Slide 15
Slide 15 text
• ϒϥβͷϦϩʔυʹΑΔ2ॏϦΫΤετΛ͙ํ๏ • POSTϦΫΤετͷྃ࣌ɺHTMLΛฦ٫͢ΔͷͰͳ ͘ɺ݁ՌදࣔϖʔδϦμΠϨΫτ͢ΔϨεϙϯεΛฦ͢ • ॲཧྃޙʹϒϥβͰϦϩʔυΛͯ͠ɺϦμΠϨΫτઌ ͷGETॲཧͱͳΔͨΊɺݩͷPOSTॲཧͷ2ॏϦΫΤετ͕ى ͖ͳ͍ • ΔϘλϯͰલը໘ʹ͔ͬͯΒɺ͏ҰαϒϛοτϘλ ϯΛԡ͞ΕΔέʔεʹແྗͳͷͰɺผରࡦ͕ඞཁ ᶄ Post-Redirect-Get (PRG) ύλʔϯ ΫϥΠΞϯτ αʔόʔ POST REDIRECT GETʢ݁Ռը໘ʣ HTML ϦϩʔυʢGETʣ 🐟
Slide 16
Slide 16 text
ᶅ ഉଞ੍ޚ • ͋ΔϓϩηεͷΈ͕ϦιʔεͷΞΫηεݖΛಠ͢Δ͜ͱͰɺ ಉ࣌ʹૢ࡞Ͱ͖ΔϓϩηεΛҰͭʹ੍ݶ͢ΔΈ • 2ॏϦΫΤετ͕ൃੜͯ͠αʔόʔଆͰ҆શʹॲཧͯ͠ޚ ͢Δํ๏ • ಉ࣌ʹಉ͡ϦιʔεΛૢ࡞͢Δͱσʔλͷෆ߹͕ى͖͍͢ • ϩετΞοϓσʔτͷ • ಉ࣮࣌ߦΛ͙͜ͱͰɺॲཧ෦Ͱߟྀ͠ͳ͚ΕͳΒͳ͍͜ͱ͕ ݮΒͤΔ 🐟 Table READ BLOCK READ
Slide 17
Slide 17 text
ᶅ ഉଞ੍ޚʙϦιʔεͷ൵؍తϩοΫʙ • RDBΛར༻͍ͯ͠Δ߹ʹ࠷؆୯ʹར༻Ͱ͖Δͷ൵؍తϩοΫ • User. fi nd(1).with_lock { … } • ૢ࡞ରʹରͯ͠ɺదͳϩοΫΛऔΕΔϦιʔε͕ଘࡏ͠ͳ͍߹͋Δ • ΞυόΠβϦʔϩοΫͷར༻ʢMySQL: GET _LOCK / PostgreSQL: pg_advisory_lockʣ • ActiveRecord::Base.connection.get_advisory_lock(“UserID#{user_id}:Payment”) • ϩοΫઐ༻ͷςʔϒϧRedisΛ͏ߟ͑ΒΕΔ • ඇಉظతʹॲཧΛͯ͠ྑ͍߹ʹFIFOΩϡʔΛ͏͜ͱ • FIFOʢFirst-in, First-outʣͷΩϡʔΛ͏͜ͱͰɺΩϡʔ୯ҐͰॱ൪ʹॲཧ͕ߦΘΕΔ ͨΊɺϩοΫΛऔಘͨ࣌͠ͱಉ͡Α͏ʹഉଞ੍ޚ͞ΕΔ 🐟
Slide 18
Slide 18 text
ᶅ ഉଞ੍ޚʙҙʙ • ഉଞ੍ޚಉ࣌ʹૢ࡞͞ΕΔ͜ͱΛ͍Ͱ͍Δ͚ͩͳͷͰɺϩοΫղ์͞Εͨ ޙͷॲཧͷରԠผ్ߟ͑Δඞཁ͕͋Δ • ଈ࣌Τϥʔʹ͢ΔͳΒ : User. fi nd(1).with_lock(“FOR UPDATE NOWAIT”) { … } • ଈ࠲Τϥʔɺಉ࣌ʹϩοΫΛऔಘͨ͠߹ʹݶΔͷͰɺλΠϜϥά͕͋ͬͯ2ॏϦΫ Τετ͕དྷͨ࣌ͷ͜ͱΛߟ͑Δඞཁ͕͋Δ • ϩοΫͷऔಘൣғʹҙ͕ඞཁ • 2ॏϦΫΤετΛ͍͗ͨAPIҎ֎ͰϩοΫղ์͕ͪൃੜ͠ɺϨεϙϯελΠϜ͕ѱ Խ͢Δͷ͋Δ͋Δͳ 🐟
Slide 19
Slide 19 text
ᶆ ςʔϒϧઃܭ • 2ॏϦΫΤετ͕ൃੜͯ͠σʔλͷ߹ੑΛอͯΔΑ͏ςʔϒϧઃܭ͓ͯ͘͠ ͜ͱͰޚ͢Δํ๏ • ഉଞ੍ޚͱҟͳΓɺಉ࣌ʹϦΫΤετ͕དྷͳ͍έʔεͰ͋ͬͯɺ͋Δ͖σʔλͷ ͕࢟อͨΕΔΑ͏ʹ͢Δ • ςʔϒϧઃܭͷํ๏ଟछଟ༷ʹ͋ΓɺશͯΛհ͢Δ͜ͱͰ͖ͳ͍ͷͰɺ ݸਓతʹΑ͘͏ํ๏Λ2ͭհ 🐟
Slide 20
Slide 20 text
ᶆ ςʔϒϧઃܭʙঢ়ଶભҠͷϧʔϧԽʙ • ঢ়ଶؒͷભҠϧʔϧΛఆٛ͢Δ͜ͱͰɺ2ॏϦΫΤετ Λड͚औͬͨࡍʹঢ়ଶભҠΤϥʔΛൃੜͤ͞Δ • ӈͷྫͩͱɺจঢ়ଶͱ͍͏ENUMͷΧϥϜʹঢ়ଶભ ҠͷϧʔϧΛఆٛ͢Δ • ʮΩϟϯηϧঢ়ଶจঢ়ଶ͔Β͔͠ભҠͰ͖ͳ͍ʯ • ʮٻঢ়ଶจঢ়ଶ͔Β͔͠ભҠͰ͖ͳ͍ʯ • ʮൃૹঢ়ଶٻঢ়ଶ͔Β͔͠ભҠͰ͖ͳ͍ʯ • RailsͩͱAASMͷgem͕͋Δ 🐟
Slide 21
Slide 21 text
ᶆ ςʔϒϧઃܭʙϢχʔΫ੍ʙ • ϢχʔΫ੍Λ͚ͭΔ͜ͱͰɺ2ॏϦΫΤετ Λड͚औͬͨࡍʹঢ়ଶભҠΤϥʔΛൃੜͤ͞Δ • ӈͷྫͩͱɺจͷঢ়ଶຖʹςʔϒϧΛׂ ͠ɺจIDʹϢχʔΫ੍ʢUQʣΛ͚ͭΔ • ΠϛϡʔλϒϧσʔλϞσϧ • https://scrapbox.io/kawasima/ΠϛϡʔλϒϧσʔλϞσϧ 🐟
Slide 22
Slide 22 text
ঢ়ଶભҠͷϧʔϧԽ vs ϢχʔΫ੍ • ঢ়ଶભҠͷϧʔϧԽͰɺϩετΞοϓσʔτͷҙ͕ඞཁ • ผτϥϯβΫγϣϯͷ༰͕ಡΈऔΕͳ͍ͨΊɺӈਤͩͱٻ → ٻͷঢ়ଶมߋΛNGͱ͢ΔΑ͏ͳϧʔϧ͢Γൈ͚ΒΕΔ • τϥϯβΫγϣϯΛషΔ߹ʹഉଞ੍ޚͱηοτͰߟ͑Δ͖ • ޙ͔Βॲཧͨ͠༰Ͱ্ॻ͖ͯ͠ͳ͍༷Ͱ͋Εෆཁ • ϢχʔΫ੍ͷ߹ɺτϥϯβΫγϣϯΛίϛοτͨ͠λΠϛ ϯάͰΤϥʔ͕ൃੜ͢ΔͨΊɺϩοΫෆཁͳར͕͋Δ • σʔλϕʔεͷ੍ศར TRN1 TRN2 *% ঢ়ଶ จ ࣌ ࣌ Table Table Table *% ঢ়ଶ ٻ ࣌ ࣌ *% ঢ়ଶ ٻ ࣌ ࣌ 🐟
Slide 23
Slide 23 text
ᶇ ϨʔτϦϛοτ • ഉଞ੍ޚ / ঢ়ଶભҠͷϧʔϧԽ / ϢχʔΫ੍͍ͣΕΞϓϦέʔγϣϯͰσʔλ ͷ߹ੑΛอͭͨΊͷΞϓϩʔν • ΫϨδοτΧʔυʹਃ͠ࠐΉͳͲɺݱ࣮ͱͯ͠ࢦఆظؒʹෳૢ࡞͞Εͳ͍ͱ্ׂ༷ ΓΕΔػೳͰ͋ΕɺΑΓ্ҐϨΠϠʔͰͷޚ͕Մೳ • ϨʔτϦϛοτ : γεςϜͷաͳෛՙΛ͙ͨΊʹɺҰఆظؒʹॲཧͰ͖Δ ϦΫΤεττϥϑΟοΫͷྔΛ੍ݶ͢Δख๏ͷ͜ͱ • ϢʔβʔIDͳͲΛΩʔʹAPIʹϨʔτϦϛοτΛಋೖ͠ɺҰఆظؒ1ճ͔͠ϦΫΤε τͰ͖ͳ͍Α͏ʹ͢Δ 🐟
Slide 24
Slide 24 text
ϨʔτϦϛοτͷϑϩʔ 📱ΫϥΠΞϯτ 🐟αʔόʔ ⚙*'/PU&YJTU ͷϩοΫ ߪೖঢ়ଶͷมߋ &UDʜ σʔλετΞ 🎁ߪೖྃ 🐟 1045QBZNFOUT nJUFN@JEJUFN@ 1BZNFOUJUFN $IFDL 63-1045QBZNFOUT *UFN*%JUFN@ 4BWF 63-1045QBZNFOUT *UFN*%JUFN@ 55-
Slide 25
Slide 25 text
ϨʔτϦϛοτͷϑϩʔ 📱ΫϥΠΞϯτ 🐟αʔόʔ σʔλετΞ 🐟 1045QBZNFOUT nJUFN@JEJUFN@ ❌'PSCJEEFO $IFDL 63-1045QBZNFOUT *UFN*%JUFN@ 💀ߪೖࣦഊ ⚙*'&YJTU$PVOU Τϥʔॲཧ
Slide 26
Slide 26 text
• Amazon API GatewayͳͲͷඪ४ػೳʢεϩοτϦϯάʣΛར༻͢Δ͜ͱՄೳ • εϩοτϦϯάͷద༻ൣғʢϦʔδϣϯ / APIΩʔ/ϝιουʣͷઃܭ࣍ୈ • ྫ: toB͚αʔϏεͷΫϥΠΞϯτຖʹAPI KeyΛൃߦ͠ɺͦͷKeyϨϕϧͰಛఆ ΤϯυϙΠϯτͷϦΫΤετΛ1ճʹߜΔͳͲ • ࡉ͔͍୯ҐͰ੍ޚ͕ඞཁͳ߹ࣗલߏங͢Δඞཁ͋Γ • rack-attack gem / throttling gem ͋ͨΓ͕ࢀߟʹͳΔ͔ • Rails 8͔Βඪ४ͰϨʔτϦϛοτͷػೳ͕ೖͬͨ ϨʔτϦϛοτͷิ 🐟
Slide 27
Slide 27 text
ᶈ APIΩϟογϡ • Ұड͚͚ͨϦΫΤετͷϨεϙϯεΛอଘ͓͍ͯͯ͠ɺಉҰϦΫΤετ͕ དྷͨ߹ʹΩϟογϡͨ͠ϨεϙϯεΛฦ٫͢Δ͜ͱͰႈੑΛ୲อ͢ΔΞ ϓϩʔν • ΫϥΠΞϯτଆ͔ΒݟΔͱ2ॏͰૹ৴ͨ͠ࡍɺͲͪΒޭѻ͍ͱͯ͠ϋϯυϦϯά Ͱ͖ΔʢϨʔτϦϛοτͱͷҧ͍ʣ • Amazon API GatewayͳͲͷػೳΛར༻͢Δ͜ͱʹΑΓɺΞϓϦέʔγϣϯͷ ֎ଆͰ2ॏϦΫΤετΛޚ͢Δ͜ͱ͕Մೳ 🐟
Slide 28
Slide 28 text
APIΩϟογϡͷϑϩʔ 📱ΫϥΠΞϯτ 🐟αʔόʔ ⚙*'/PU&YJTU ͷϩοΫ ߪೖঢ়ଶͷมߋ &UDʜ σʔλετΞ 🎁ߪೖྃ 🐟 1045QBZNFOUTJUFN@ 1BZNFOUJUFN $IFDL ,FZ1045QBZNFOUTJUFN@ 4BWF ,FZ1045QBZNFOUTJUFN@ 3FTQPOTF#PEZYYYY 55-
Slide 29
Slide 29 text
APIΩϟογϡͷϑϩʔ 📱ΫϥΠΞϯτ 🐟αʔόʔ ⚙*'&YJTU 3FTQPOTF#PEZͷऔಘ σʔλετΞ 🎁ߪೖྃ 🐟 1045QBZNFOUTJUFN@ 1BZNFOUJUFN DBDIFE $IFDL ,FZ1045QBZNFOUTJUFN@
Slide 30
Slide 30 text
• ΩϟογϡΛ͏͜ͱͷҰൠతͳࠔ͞ʹཱ͔ͪ͏ඞཁ͕͋Δ • ΩϟογϡͷKeyΛͲ͏͢Δ͔ʁ • ΩϟογϡͷTTLΛͲ͏͢Δ͔ʁ • ΩϟογϡͰ͖ΔαΠζͷݶք • GET·ͩ͠ɺPOSTܥͷAPIΛΩϟογϡͯ͠ྑ͍ͷ͔ʁ • Ωϟογϡ͕อଘ͞ΕΔ·Ͱͷؒʹൃੜ͢Δ2ॏϦΫΤετແྗ APIΩϟογϡͷิ 🐟
Slide 31
Slide 31 text
• ΫϥΠΞϯτ͕ϦΫΤετΛҰҙʹࣝผͰ͖ΔใʢIdempotency KeyʣΛ HTTPϔομʹ༩͢Δ͜ͱʹΑΓႈͳAPIΛߏங͢ΔΞϓϩʔν ᶉ Idempotency-Keyϔομ 🐟 📱 https://speakerdeck.com/ohbarye/safe-retry-with-idempotency-key-header https://speakerdeck.com/ohbarye/my-favorite-protocol-idempotency-key-header
Slide 32
Slide 32 text
Idempotency-Keyϔομͷϑϩʔ 📱ΫϥΠΞϯτ 🐟αʔόʔ ⚙*'/PU&YJTU ͷϩοΫ ߪೖঢ়ଶͷมߋ &UDʜ σʔλετΞ 🎁ߪೖྃ 1045QBZNFOUT nJUFN@JEJUFN@= )t*EFNQPUFODZ,FZYZ[u 1BZNFOUJUFN $IFDL ,FZYZ[ 4BWF ,FZYZ[ 3FTQPOTF#PEZYYYY 55- 🐟 📱 ,FZ࠾൪
Slide 33
Slide 33 text
Idempotency-Keyϔομͷϑϩʔ 📱ΫϥΠΞϯτ 🐟αʔόʔ ⚙*'&YJTU 3FTQPOTF#PEZͷऔಘ σʔλετΞ 🎁ߪೖྃ 1BZNFOUJUFN DBDIFE 🐟 📱 1045QBZNFOUT nJUFN@JEJUFN@= )t*EFNQPUFODZ,FZYZ[u ,FZ࠾൪ $IFDL ,FZYZ[
Slide 34
Slide 34 text
APIΩϟογϡ vs Idempotency-Keyϔομ • Idempotency KeyϔομAPIΩϟογϡΑΓෳࡶ͕Ώ͑ʹॊೈ͔ͭݎ࿚ʹႈͳAPIαʔ όʔΛ࡞ΕΔ • ΫϥΠΞϯτ͕Λ࠾൪ͯ͠ઃఆ͢ΔͨΊɺႈͷൣғ͕APIΩϟογϡΑΓݫີ • ಉҰͰͷૢ࡞Λผ͢Δ͜ͱ͕Ͱ͖Δ • ಉҰͰͷϦτϥΠૢ࡞ͱɺ1͔ΒͷΓ͠ͷૢ࡞ผͰ͖Δ • ະॲཧ / ॲཧத / ॲཧࡁΈͱࡉ͔͘ॲཧεςʔλεΛཧͰ͖Δ • ةݥͳߋ৽ܥͷૢ࡞ʹରͯ҆͠શʹႈੑΛ࣋ͨͤΔͨΊʹɺAPIΩϟογϡΑΓ Idempotency-Keyϔομͷํ͕༏Ε͍ͯΔ • ෭࡞༻͕গͳ͍؆қతͳૢ࡞Ͱ͋ΕAPIΩϟογϡͰेͳέʔε 🐟 📱
Slide 35
Slide 35 text
ᶊ ETag ʴ If-Match • ETagʢEntity Tagʣͱ͍͏ߋ৽ରͷόʔδϣϯΛλά ཧ͠ɺIf-MatchϔομͰ͖݅ߋ৽ϦΫΤετΛૹΔ͜ ͱͰ2ॏϦΫΤετΛ͙ํ๏ʢָ؍తϩοΫʣ • αʔόʔଆͰɺΫϥΠΞϯτ͔ΒૹΒΕͨETagͷΛ ൺֱ͠ɺόʔδϣϯ͕Ұகͨ͠ΒॲཧΛߦ͍ɺෆҰகͷ ߹ʹ412 Precondition FailedΛฦ٫͢Δ • ӈͷྫͩͱόʔδϣϯΧϥϜΛETagͱͯ͠ར༻͢Δ͜ͱ Ͱ͖Δ͠ɺ༰ͷtext͔ΒHashΛٻΊͯETagͱ͢Δ͜ ͱՄೳ 🐟 📱
Slide 36
Slide 36 text
ETag ʴ If-Matchͷϑϩʔ 📱ΫϥΠΞϯτ 🐟αʔόʔ ⚙*'7FSTJPO.BUDI ͷϩοΫ &UDʜ σʔλετΞ 🎁ߪೖྃ 1045QBZNFOUT nJUFN@JEJUFN@= )t*G.BUDIu 1BZNFOUJUFN (FU*UFN 7FSTJPO 🐟 📱 (&5JUFNTJUFN@ &5BH 6QEBUF*UFN 7FSTJPO $IFDL $VSSFOU7FSTJPO
Slide 37
Slide 37 text
ETag ʴ If-Matchͷϑϩʔ 📱ΫϥΠΞϯτ 🐟αʔόʔ ⚙*'7FSTJPO/PU.BUDI Τϥʔॲཧ σʔλετΞ 1045QBZNFOUT nJUFN@JEJUFN@= )t*G.BUDIu ❌1SFDPOEJUJPO'BJMFE (FU*UFN 7FSTJPO 🐟 📱 (&5JUFNTJUFN@ &5BH $IFDL $VSSFOU7FSTJPO 💀ߪೖࣦഊ
Slide 38
Slide 38 text
• ָ؍తϩοΫͰ͍Ͱ͍Δํ๏ͳͨΊɺมߋ͞Ε͍͢Ϧιʔεͷಋೖʹෆ͖ • ྫ͑ECαΠτͷߪೖͳͲɺෳਓ͕ಉ࣌ߪೖ͢Δέʔεʹ͍͍ͯͳ͍ • ϢʔβʔͷϓϩϑΟʔϧߋ৽ͳͲɺ1ਓ͔͠ฤू͠ͳ͍έʔεʹ͍͍ͯΔ • ΫϥΠΞϯτ͕ϔομΛ༩͢Δ͜ͱͰ2ॏϦΫΤετͷରࡦΛ͍ͯ͠ΔͰ Idempotency-Keyϔομͱಉ͕ͩ͡ɺతʹҧ͍͕͋Δ • Idempotency-Key : ϔομͷKeyใΛͬͯɺႈͳAPIΛఏڙ͢Δ • ETag ʴ If-Match : ָ؍తϩοΫͰҟͳΔΫϥΠΞϯτؒͰͷಉ࣌ߋ৽Λ͙ ETag ʴ If-Matchͷิ 🐟 📱
Slide 39
Slide 39 text
• 1ͷΈ༻ՄೳͳτʔΫϯΛൃߦ͢Δ͜ͱͰ2ॏϦΫΤετΛ͙Ξϓϩʔν • 2ॏϦΫΤετͷతҎ֎ʹɺਖ਼ͳϦΫΤετͰ͋Δ͜ͱΛอূͯ͠վ͟ΜΛ͍ ͩΓɺ༗ޮظݶΛઃ͚Δ͜ͱͰΑΓηΩϡΞʹ͢ΔͳͲෆਖ਼ରࡦతͰΘΕΔ • τϥϯβΫγϣϯτʔΫϯνΣοΫͱ͍͏ݴ༿Ͱհ͞ΕΔ͜ͱ • CSRFτʔΫϯτʔΫϯΛͬͯϦΫΤετΛνΣοΫ͍ͯ͠ΔͷͰࣅ͍ͯΔ͕ɺ CSRFରࡦͷจ຺ͰτʔΫϯ͕ϫϯλΠϜͰ͋Δ͜ͱඞਢͰͳ͍ ᶋ ϫϯλΠϜτʔΫϯ 🐟 📱
Slide 40
Slide 40 text
ϫϯλΠϜτʔΫϯͷϑϩʔ 📱ΫϥΠΞϯτ 🐟αʔόʔ ⚙*'5PLFOJT7BMJE ͷϩοΫ &UDʜ σʔλετΞ 🎁ߪೖྃ 1045QBZNFOUT nJUFN@JEJUFN@= nUPLFOYZ[ 1BZNFOUJUFN *TTVF UPLFOYZ[ 🐟 📱 1045UPLFOT 5PLFOYZ[ %FMFUF5PLFO $IFDL UPLFOYZ[
Slide 41
Slide 41 text
ϫϯλΠϜτʔΫϯͷϑϩʔ 📱ΫϥΠΞϯτ 🐟αʔόʔ ⚙*'5PLFOJT*OWBMJE Τϥʔॲཧ σʔλετΞ 1045QBZNFOUT nJUFN@JEJUFN@= nUPLFOYZ[ ❌'PSCJEEFO *TTVF UPLFOYZ[ 🐟 📱 1045UPLFOT 5PLFOYZ[ %FMFUF5PLFO $IFDL UPLFOYZ[ 💀ߪೖࣦഊ
Slide 42
Slide 42 text
ޚࡦͷ·ͱΊ
Slide 43
Slide 43 text
ᶃ αϒϛοτϘλϯͷ੍ޚ ᶄ Post-Redirect-Get (PRG) ύλʔϯ ᶅ ഉଞ੍ޚ • Ϧιʔεͷ൵؍ϩοΫ • FIFOʹΑΔॱং੍ޚ • ΞυόΠβϦʔϩοΫ ᶆ ςʔϒϧઃܭ • ঢ়ଶભҠͷϧʔϧԽ • ϢχʔΫ੍ հͨ͠ޚࡦͨͪ ᶇ ϨʔτϦϛοτ ᶈ APIΩϟογϡ ᶉ Idempotency-Keyϔομ ᶊ ETag ʴ If-Match ᶋ ϫϯλΠϜτʔΫϯ
Slide 44
Slide 44 text
αϒϛοτϘλϯͷ੍ޚ ޚࡦͷάϧʔϐϯά Idempotency-Keyϔομ ETag ʴ If-Match ϫϯλΠϜτʔΫϯ ΫϥΠΞϯτͰͷޚࡦ ΫϥΠΞϯτͱόοΫΤϯυͰͷޚࡦ όοΫΤϯυͰͷޚࡦ Post-Redirect-Get (PRG) ύλʔϯ ഉଞ੍ޚ ςʔϒϧઃܭ ϨʔτϦϛοτ APIΩϟογϡ 🐟 📱 🐟 📱
Slide 45
Slide 45 text
ൃදऀͷߟ͑ • جຊαϒϛοτϘλϯͷ੍ޚ / PRGύλʔϯ / ഉଞ੍ޚ + ςʔϒϧઃܭΛߦ ͳ͍ͬͯΕेͳέʔε͕ଟ͍ • σʔλͷ߹ੑ͕֬อ͞ΕΔΑ͏ςʔϒϧઃܭΛ͍ͯ͠Εக໋తͳى͖ͳ͍ • 2ॏϦΫΤετࣗମɺશମͷϦΫΤετ͔ΒݟΔͱΤοδέʔεʹͨΔͷͰɺ2ॏϦ ΫΤετ͕ൃੜͨ͠ࡍͷඃಘΒΕΔϝϦοτΛఆͯ͠ɺదͳΞϓϩʔνΛબ ͖͢ • ϫϯόϯΫͰ࣮ࡍʹར༻͍ͯ͠ΔޚࡦΛཧ༝ͱͱʹհ
Slide 46
Slide 46 text
ϓϦϖΠυΧʔυ / ೖۚ / ग़ۚ Citadel / ֎෦αʔϏεґଘ
Slide 47
Slide 47 text
Idempotency-Keyϔομ • ΫϥΠΞϯτଆͰ࠾൪ͨ͠KeyΛͬͯႈͳAPIΛߏங ͢Δํ๏ • ֎෦αʔϏεͷॏཁͳૢ࡞Λߦ͏ॲཧͰଟ͘ར༻ • ίϯϏχ / ϖΠδʔͳͲͷೖۚใΛൃߦ͢Δॲཧ • ΫϨδοτΧʔυೖۚΛ͢Δࡍͷ3DSೝূॲཧ • ۜߦޱ࠲͔ΒҾ͖མͱ͠ॲཧ
Slide 48
Slide 48 text
Idempotency-Keyϔομ • ֎෦αʔϏεͱͷ࿈ܞॲཧෳࡶʹͳΓ͕ͪ • ෳͷDB τϥϯβΫγϣϯ͕ඞཁͰഉଞ੍ޚ͕ෳࡶʹͳΔ • ࣗαʔϏεଆͱ֎෦αʔϏεଆͷ྆ํͰσʔλෆ߹͕ൃ ੜ͢ΔՄೳੑ͕͋ΓɺϦΧόϦॲཧ͕େม • Idempotency-KeyϔομΛར༻ͯ͠ຊॲཧͷલஈͰ2ॏ ϦΫΤετͷରࡦΛߦ͏͜ͱͰɺσʔλෆ߹͕ൃ ੜ͢ΔϦεΫΛݮΒ͢͜ͱ͕Ͱ͖Δ ֎෦αʔϏε ݺͼग़͠ લॲཧ τϥϯβΫγϣϯ ޙॲཧ τϥϯβΫγϣϯ ֎෦αʔϏεݺͼग़͠ॲཧ Idempotency-Key ϔομʹΑΔޚ
Slide 49
Slide 49 text
Idempotency-Keyϔομ • ࣄނతͳ2ॏϦΫΤετͱҙਤతͳผϦΫΤετΛ۠ผ͢Δ͜ͱ͕Ͱ͖Δͷັྗత • ྫ͑ϓϦϖΠυΧʔυͷೖۚॲཧ࣌ؒͰෳճߦΘΕ͓͔ͯ͘͠ͳ͍ • Key͕ಉ͡ = ࣄނతͳϦΫΤετɺKey͕ҟͳΔ = ҙਤతͳϦΫΤετͱ۠ผͰ͖Δ • ҰํɺKeyͷνΣοΫॲཧొॲཧͳͲͷΦʔόʔϔου͕૿͑ͨΓɺΫϥΠΞϯτଆ ͰͷKey࠾൪ॲཧͷ࣮ͳͲ࣮ίετ͕͔͔ΔͨΊɺಋೖՕॴݶఆత
Slide 50
Slide 50 text
ϫϯλΠϜτʔΫϯ • ΞϓϦͷதͰಛʹॏཁͳॲཧͰ༻ • ύείʔυͷొ / ࠶ઃఆ • Χʔυ൪߸ͷදࣔ • ͋ͱΒ͍νϟʔδۜߦޱ࠲Ҿ͖མͱ͠ͳͲͷೖۚ ॲཧ
Slide 51
Slide 51 text
ϫϯλΠϜτʔΫϯ • Ϣʔβʔͷࣄނతͳ2ॏϦΫΤετΛࢭ͢ΔతͰͳ͘ɺϦΫΤετ༰ͷ౪ௌͳͲ ʹΑΔϦϓϨΠ߈ܸΛ͙తͷͨΊʹ༻ • ϦϓϨΠ߈ܸ : αΠόʔ߈ܸͷҰछͰɺ௨৴ͰҰૹ৴͞Εͨਖ਼نͷσʔλΛड͠ɺͦ ͷ··࠶ૹ৴͢Δ͜ͱͰɺෆਖ਼ͳಈ࡞Λ༠ൃ͢Δ߈ܸ • ೖۚॲཧ͕౪ௌ͞ΕͯԿෆਖ਼ೖۚ͞ΕΔͳͲͷ߈ܸΛ͙ • ࣄނతͳ2ॏϦΫΤετΛ͙ͨΊɺIdempotency-KeyϔομͱΈ߹Θ࣮͍ͤͯͯ͠ ΔAPIଟ͍ • τʔΫϯऔಘϑϩʔͳͲ࣮ίετɺϢʔβʔͷख͕ؒൃੜ͢Δํ๏ͳͷͰɺ࣮Օॴ ηΩϡϦςΟڧΛ্͍͛ͨՕॴͷΈ
Slide 52
Slide 52 text
ϨʔτϦϛοτ • όʔνϟϧΧʔυͱ͍͏ཧతͳΧʔυൃߦ͞ΕͣΧʔυ ൪߸͚ͩೖखͰ͖ΔػೳͷൃߦॲཧͰར༻ • όʔνϟϧΧʔυԿͰ࠶ൃߦͰ͖Δ͕ɺ࣌ؒʹԿ ࠶ൃߦ͢Δ͜ͱਖ਼ৗͳঢ়ଶͰͳ͍ • ؒҧ͑ͯΧʔυൃߦ͕ى͖ͨࡍ֎෦αʔϏεଆͷमਖ਼ඞ ཁͰӡ༻ίετ͕ߴ͍ • Χʔυൃߦ2ͭͷαʔϏεʹލͬͯॲཧ͞ΕΔ͕ɺΧʔυൃ ߦଆͰϩοΫΛऔಘͰ͖ΔదͳϦιʔε͕ଘࡏ͠ͳ͔ͬͨ • ϢʔβʔຖͷൃߦճΛอଘ͠ɺࢦఆճΛ͑ͨΒΤϥʔ ൃੜ͢Δ༷ʹ ϞόΠϧΞϓϦ #'' *TTVJOH"1* $PSF"1* ֎෦αʔϏε
Slide 53
Slide 53 text
ϨʔτϦϛοτ • ഉଞ੍ޚͰ͖ΔΑ͏ʹطଘͷΈΛमਖ਼ͨ͠ΓɺΞυ όΠβϦʔϩοΫݕ౼͕ͨ͠ίεύ؍Ͱෆ࠾༻ • ϨʔτϦϛοτͷ੍ޚςʔϒϧΛҰͭՃ͢ΔఔͰ࣮ݱ Մೳ • Idempotency-Keyϔομͷಋೖݕ౼͕ͨ͠ɺΧʔυൃߦ αʔϏεଆʹͦͷΈ͕͍ͬͯͳ͔ͬͨͨΊෆ࠾༻ • ໓ଟʹൃੜ͠ͳ͍͕ɺ͠ൃੜͨ͠Βσʔλमਖ਼ͷӡ ༻ίετ͕ߴ͍ΛίετͰղܾ https://blog.smartbank.co.jp/entry/2025/03/19/123000
Slide 54
Slide 54 text
ςʔϒϧઃܭ + Ωϟογϡ • ίϯϏχ / ϖΠδʔͳͲͷೖۚํ๏ͰɺϢʔβʔ͕ϨδͰ͓ۚ Λࢧͬͨޙʹྃใ͕WebhookͰૹΒΕΔ • WebhookʹϦτϥΠػೳ͕ఏڙ͞Ε͍ͯΔ͜ͱ͕ଟ͍ • λΠϜΞτ͕ൃੜ͢Δͱ֎෦αʔϏεଆʹΤϥʔผ͞Εͨ ͚Ͳ࣮ࡍʹޭঢ়ଶͱ͍͏σʔλෆ߹͕ൃੜ͢Δ • ϦτϥΠ࣌ʹɺςʔϒϧઃܭͰ߹ੑΛอ͍ͬͯΔ͔ΒͱΤϥʔ ൃੜͤ͞ΔͱΤϥʔϧʔϓ͕ൃੜ͢Δ • ֎෦αʔϏεΛར༻͍ͯ͠Δͱ͖ɺIdempotency-Keyϔομͳ ͲͷΫϥΠΞϯτଆͷมߋ͕Ͱ͖ͳ͍ ֎෦ αʔϏε αʔόʔ POST TIMEOUT RETRY ? DB Table SAVE SUCCESS
Slide 55
Slide 55 text
ςʔϒϧઃܭ + Ωϟογϡ • ςʔϒϧઃܭ্Ұҙ੍ΛೖΕΔͳͲͰ߹ੑΛ֬อ͓ͯ͠ ͖ɺWebhookΛड͚औͬͨࡍʹରϦιʔεͷঢ়ଶΛ֬ೝ ͠ɺॲཧ͍ྃͯͨ͠ΒޭΛฦ͢͜ͱͰႈʹ͢Δ • ͨͩ͠ႈʹ͢ΔϦΫΤετΛಛఆͰ͖ΔIDͳͲؚ͕·Ε͍ͯͳ ͍ͱ࣮ݱͰ͖ͳ͍ͷͰɺ֎෦αʔϏεͷ༷࣍ୈ ֎෦ αʔϏε αʔόʔ POST TIMEOUT RETRY SUCCESS DB Table SAVE FETCH SUCCESS
Slide 56
Slide 56 text
·ͱΊ
Slide 57
Slide 57 text
·ͱΊ • ୭ʹͱͬͯۙͰॏཁͳ2ॏϦΫΤετʹ·ͳ͍͍ͯ͘ੈքΛ࡞Δ • 2ॏϦΫΤετ͕ͲͷΑ͏ͳͳͷ͔આ໌ • 2ॏϦΫΤετͷޚ๏Λ9ݸհ • ϫϯόϯΫͰͷϢʔεέʔεͱ࠾༻͍ͯ͠Δޚ๏Λհ • ۀͰʮͲ͏͠Α͏ʯͱͳͬͨ࣌ʹͥͻݟฦ͍ͯͩ͘͠͞ʂ • ࠓൃදͨ͠ύλʔϯΛ୯ಠ or Έ߹ΘͤΔ͜ͱͰͳΜͱ͔ͳΔέʔε͕ଟ͍ͣ
Slide 58
Slide 58 text
No content