namespace App\Http\Middleware; use Closure; use Illuminate\Http\Request; use Illuminate\Support\Facades\Storage; class CacheToR2 { public function handle(Request $request, Closure $next) { return $next($request); } // Hàm terminate chạy ngầm sau khi server đã trả HTML cho khách public function terminate($request, $response) { // Chỉ bắt request GET, status 200 và là file HTML if ($request->isMethod('GET') && $response->status() == 200 && str_contains($response->headers->get('Content-Type'), 'text/html') ) { $path = $request->path(); // Danh sách các route bỏ qua không lưu cache if ($request->is('admin/*') || $request->is('api/*') || $request->is('login')) { return; } // Đặt tên file giống với logic của Worker $r2Path = $path === '/' ? 'index.html' : $path . '.html'; // Lưu ngầm lên R2 try { Storage::disk('r2')->put($r2Path, $response->getContent(), [ 'ContentType' => 'text/html; charset=utf-8', 'CacheControl' => 'max-age=31536000' ]); } catch (\Exception $e) { // Ghi log nếu có lỗi (chưa config đúng S3/R2 chẳng hạn) \Log::error('R2 Cache Error: ' . $e->getMessage()); } } } }namespace App\Http\Middleware; use Closure; use Illuminate\Http\Request; use Illuminate\Support\Facades\Storage; class CacheToR2 { public function handle(Request $request, Closure $next) { return $next($request); } // Hàm terminate chạy ngầm sau khi server đã trả HTML cho khách public function terminate($request, $response) { // Chỉ bắt request GET, status 200 và là file HTML if ($request->isMethod('GET') && $response->status() == 200 && str_contains($response->headers->get('Content-Type'), 'text/html') ) { $path = $request->path(); // Danh sách các route bỏ qua không lưu cache if ($request->is('admin/*') || $request->is('api/*') || $request->is('login')) { return; } // Đặt tên file giống với logic của Worker $r2Path = $path === '/' ? 'index.html' : $path . '.html'; // Lưu ngầm lên R2 try { Storage::disk('r2')->put($r2Path, $response->getContent(), [ 'ContentType' => 'text/html; charset=utf-8', 'CacheControl' => 'max-age=31536000' ]); } catch (\Exception $e) { // Ghi log nếu có lỗi (chưa config đúng S3/R2 chẳng hạn) \Log::error('R2 Cache Error: ' . $e->getMessage()); } } } }}ksǑwx$ .AF4>gQ?#,vooذ(Veޅ:↫ˬA B"0]̬̬K/ 2%M,|7T}UbCcynO}.ͱ}J˭A;]޺}sWm޻ F__ӾqG}}Dj1mU#˴kXk%-kJ529TWWU(?r xl[4ݮt2ܪm{uP\U@E`/< Uin8QAA;M27?ݹF:o͓㟒['utnCvNLrs!N# 8yGTo,-4jr`5Q(LBnv3ߴA@{'?FqrCK3U|+OϚ(ȺǵrOugzb -e׆+K,h;TGOM9s@ X4 @:iNUHEWzۮJ5Dp(&U_Ul쫾iٰD IvXRP 㹂%j4k%Pcي[aV1.5-?Zn8 @9}M؟=},<ȔBWMߊ k5rNʕ5dJ}j| F.9QQOTJĦV)F}JjKDm rѪ#"`jjxCRZnB)b\ PPN8PEO%B=(q%5V)@;wE9taݧ@+,NԌcA9dHWZ=~`V05*EI[Jj D8ʠwFhp:a<tf<'U@LHO%=5& X7Su YqqpQea"d%Ց@gИᤆT~0 .<%G`yzjݐSt@x9p^T:%1X'a_"C*DW=z石{]'wb-3ay\VͿHİFmXL1m&wh "ĀNo*!v0&u /RNѠnNG̟,p'˵J㷙X9,7BG~[\Jo£@йk*!&>\Wӡ.'|W4[{ O}y:c=;f3ιT ݥ`~6yfaK J(5(m3}tr?34.WYA|=A*2pPwt?$A?Zzt!֬`[_~C?Ro!|S-KNwG hĮs xFZ m" :62t2Ҽh.eA^&Ru=jjzJ_g p!tThy.Bic<99Iɮs$V-S< %DvN٭ )9 ȈD#1AF@ǡ{k%!DNGwE]ICzYAj5&Kf93nzC3$=~w[% 1SD[169HLR^KԤDea Ee] K5$GK 0thXX9y[U5qusp ({XKilQ(/7{PGJg8mOa\hY#6֧΀ylE'|9R3m3tHRfM,su0.BH>[i3p`ތLt$z:v&u}NOmh~mi&ǧer=bNN`1RO]" LBw0KUT}Z %FfkFߺd##IB%Ȕ$ m L{0Xk ҧd0ZQWq bQM;-J;?0}1ds/VW46h&ӱ,Z5ܽ3Zfd2}DpvJ7Oߋ6a9X[v\y|Ww%@_4hKmLUYh QNOl˖rDVX"F]y԰ZtwY̌" ĺEd^膎^ws;cxƊ4F6!a0,"jQ~^<~"oj12Ty58P`>_jHP GVvXB.'Q1I6֚3E0Ӄ}6b8}\Q@>eY@)AmNS| IR'jbp0I? =BH>vO}>"gY7.*z(Ô05(~Oz8aR4D^~QiqS1yRk.boV?%[tB)8-/jvqNniyLVg4W1zzpKx3MqxMd!@8vYK-r\CBݢ`z@St!.fpĕ[I0CMMPJ`>&4ڤ?0@A]ܦS gm-h!%!ٹ[4%ayϷ8Bd,XnH%#/3^[)nVf~Ȗ\PS}}jd}*i ;/9E>TTjAKx=[r9[=(hn/`(h ߢ|m]3J R˸>`&xI<9{{sDz "ZYed!q2r2I}WzeEuޢD*rS:0 %ѱ/rKed{=& a-!XTzfbQi1;?5Mrn=J*}Oi`3![lnXɉMT:y6Gzр.L =i<}NK`+P?u$yzE c"왿Zxp" $A D5(Z\dg=9Gu},;PR~7|{6SeԠ#sgee_cۦΕ5˕㜑n*&WX\P)>6өZw0-]=#K~XzI {'&ie,hAsza[x^hT$.MG(q Ku<_.*`sr3(Dr{@rZJQAwv0Gv_;[pA~jn0좸Y!~x4׸g2nDhհ&=PzSl]~{ʾ&+2V>D{mh<*:5L݀/2RSBYzbB~$Fy(&;pLf⪄1R]w( RS7#n&@X`Vxk҉oK,vzjxhG_+])EGf8yc +f,g {r,NF1oYxgف%>FZG?aՁheKɞMhőn"Xl]d yP# bC|y~2Y*^ :2LXL3[5b!tpEG`@CEw@]~{l|ᡞFTLh ˋ]ˈ_[y +A?.%]D=&ϥT2X540-tϧ>2Oݜp1|d =&ʦ)z}udF@cl %U[`SY)䫙Qͪ姩eYOα*ЯG43F&^5j/=YaNތϫ$NKa?oM4u@ } ~{&jmܸqeD6R "Rtbݤ*Oc((J0Yi^T0f=N\xpt4 42 (e&zAeǑIv_=", S45v肒R9XPd+YeA,.,I*Cũc&)*• h 5[Xy D}vXZ5%LfxzK;<Ó㷇k =~JѸ +ӯ+#rOp` )3tP_=CŌjCW4,n00@6/Q'X}̤Ǥ}@{`榄)lo%#ESt Ԩa Az`*`ت[qF/SiͅWw]qaū76[//\R΅-^d~%o9h3\ӋMО^4̾)^Z* D&A,<d4)FLq3hJ^l#&#&8`5z|PB)9Qn]UG.H(:wLe`!rQm7rQ pUSƓ% ;OԾE_=sKn"ַoZTI^weVˋy'-hh.A螈_x[c5 HU3[g ͕i  0LiO4ߤ4[>W4uleIikb;>%R;aFjEYm,,ǺC6*UiUq /l9V{LV&He12u&;b9*S wUWqZ:aHM=vf'M*&7hIa%fW38(MοJ(8-7fSiRH fm0hrt]uqi=Y2Ӹnw+ |9-63tY!7އfi]L =ӈKg6-.ޥR4, [>#e@C; O[L֘ o70A?V!wMb<] ;@V:hg(a O*MvP~;=_(=v>e\By<9,ɴS`Z,NA+G7 (~V!Mҟ$!mK)z9W&{NܙC&;8c}/>i74hYP⣌}>!`,=/W 6'{g Ims&`oXajili` fP牗GH $YN)OQTnIb)b>L6g(%sS ڈZ6⧜lK86J82TΌK*3\v1%9M% 7Kjfzq£ot˼f[ws$`2/JcSl3~4Ǵҝ Fs^` n<#)1G{tb]_|{0PGk &V}ez0gC￁6{dɣ!7nr/duaq+-P@m) VgwM8+ӎag̢+&2okfy|whO17ÕPS=TB rD"f:^< R]\7 F3Ir`*]Ӱg$[_tl\?9sJ1nInmBlߑfoH6'mMEp Hop%cS@V+FN*įCTF@y38R(ef֗>oAi,h,VR$]*^hcgRI<ql[;$G[?BAa; rcs3J% FYlr ]MS\*Lovn0zhp+rsXX/4OW|4lEW@oyUK!D2(4|,;sV[X[}ܽ R%I1`HGH7Z瑌[:طb#eipGٺu/xc+ңV6: CU =;:MLHZeg GFY_YZYXθ (u}(Ew<c\j}]:zO]!>> P%xd~ΰn՜žc{";/n`sG-zc/0>zOs9&s E'␝߇/Nnz*vkמS&QzFGr9` j=ҨGtKZK^ ;^XJ:Z^)h8"zʷ&'dn_Pz2\3SD+ 5Vsm0_.;:||W3Ƭ,^k= J'_l5a"aR4=t\ZK+ej3$\&[qz&#sEisW {lֳTj]G)􀪳@5D0SH>˶R]"[h [xu}ψ᪙)U=Zm٫˭* : 28~C?aꫯ5(-t|p#@g\Z>_Nˌ, q>ủRe="` Y3 ]#٨}$C8{ѷAxh; eQCy!%qJo4Θ %- ]5qgTJ`0l;H0I\AƐ͎.gX2sKp.=kp$E=ّ&ggӃf*@:>Ci[8#)rp4HXIz`x'hLVHՓbrYJ`zk:;;f$]t3Ɛvg g=.͹4ɶP ęԖOT 3Gl Ä=qjfdγ S֟ ij͐Fi>A$\oJlg. Y?X/4SSl1SZ<e`ӂvx~&œ3S<~{@ 8͒>(>Tf.y6I>=a4}xCգ5sܧtv5wCbKZ`dx(b& ^fz  kQDS#k;T{^ֆǁ|S?9縆쎩ܢO^@3_ ӤZt}XRUށoU%`៲yBSaxZX"k%K Y*gRZϹ%\GN 9ަHKP8ڬG/ ܾi>L4L/IPWwek"7R'ktZ>;A,*+a&,: P-'ʜ*V|z=k^ 9 . 9g٣N1m#r0T}m@SWW4 &>~'`WDpLI>9`c/8]BwF[z"$_ dNxl+p X*SA8 4o8_n).}_)*Aǘ Sx2e_%#UGJP$bˀ^'WXNtxȇ+@՝C 6~Wk*P! WKzvjiSIDG!زx.r)?|lF[FN3Z3H124]pj-wSPZADͤ8z3q5&ޮFr)GLOl{wJpKSGd\] 7)'ڔO]D0 ui:姙U~0>\|A&%+2junj`ȫ̊B1[360Q۔o 2z~cayaaIpo*=hKVe;qMo{Tf$I-fT#AԥF )Ihu M"xY: X33V;#Jdʦ]rS3i5XnZ$٪uH޴Z[0PYXg`a玆ߏ)(z#%A|,_J=e'rJf ʫ^BKs‘"O\Ix#dD<7y3ֻd4zMcA$ =*3?$ä&'E21V|=9Q d}>t嘞蝴\>cU=IMcyJ$3a hD;>ɣOl.ޓ9ѯX= ;k7.Nvo Dqǘ),C6+қeEѝi9ojԵJQeE\W(IMt g<@2]WA B1roIl!_WZYEנߦAw 7, Q]jTu`nL^m3=5|0W.}%Q ( ?)N\TD`VT.MGsĜ@(٪ޗd*-TA:JڭOO+Jyp"Hćf.LJAj,stpPn*w?ˠᐣxm6f ia,$M@0?!P{$P/' #įNe1PaUlB86aĈF7MRe:Bد#eb;W4aؼقM]0(ăS9SۚnjEu>:T߹{G3?>vS(hTçώBd0R׍~|}n`ERm~@jE6 !u5Ib3O+Y]Г9^f(]%FFdp<|kMtC[U{~*OvZwi顦h'QCӂ/}ˇ DF)Gdw1vJ8UC!IH!F1 Lz1rBxz}q r5@ Sq sJ TDߖK+}mG2]?8r; A).aYYkpQ (dU v(s)Ƶ@.bzo/Mlj,i9YR^`ӵen>)`]Z0 T hװ wܹrY:{e/%59~ AB! . 2JAq`<[+][`<M`¸L:kecLpn$Mcd2E~b Ap""9-k.B_\RO!mjvCbwaI4Mj B4le෹nTf5RN2GYpM]UG#7ђt!5b%)GG7"g>91&ϏFEEI):m>l+c8ClP2T?;/43pzs lEs5Cɤ(@m@DЏ9:x祗@AVMo͠(6? D{r߀Z 80)Lc34!hN.WDzpDjdhz͎u5P4gĩ]- u t@gUETWCMY*erʁ lt$(K@`7Mg8Tm$U`sy- 2aīU\%erazzHA! i g1y7p?kXPG2iIf>N2B EiPc5N;&#Ɩjt+BrqtQ?iJqLÓ2VQ)fHxď .*&T-y>>ȫ#Ő>)CNfBQƵ694tIhfr?L8,9 @pdAѨvw%iJv`4ZgH3`RYk BgPSOH3]c^fVRVv|- l.j soj]JHV=7Wr$ X`֯2c"-ÒI/Dw XԀ+t囦?(Cwonoi־i:CQot \ed?KgUzB*97eg.O4?GJKEBq9Uh %Z-2 VS h9XLovk M]C0}I#5 G*ɵf.Zl1OL4=1(9Xc=@/ǐJHbXQ0\2\'2ԾAZ8ѡ"X:mGp|JF!Z@dbO<( CpJgX-o*4>Mhe:=z^8]0{$TӖahT޻ xI)[rNPatsԿ۠Tv1255_rc._s@+tk#[#۬e4EG﬚vy%; C4JXRsd:(#>ᴘ/o] y"?PmLPTa|.m,ݞzV {x:Kw̐,{#7:]$tŤC5ߙ_'> r*x@,_>^&O,&Txǀ2t}뛌)6)fZٌdL1071j xltt&vd=A9&v&(#CJs„x1||tx^q;J1]zFy7fʱuͤg}*\/} g M3TG8cYai}ˇ<ޞsȖ!q4$[ z4%c8GT ]LD0"^.x`rHRoWF@뉗'DXA-Os$KGA7fJa$F`G Uۿx`zf״pAD#js7.ҐeE33 _1QkKEti\ZIi}UZSl~/Lf_JV;0;xXdc^ Jd!XAZlC UJeGe]{SthłDUQ\W6 xd)&S@oZOa -٨hA{s`HЌzKwǿ?#4z.jꦓ 1Gd .oh$Uh*f8WWx|a# :s;kstL{Hktrw.*?3Dl=Ytnx_l,81dDH!qD%Xla,C=`VlxGљ^R^Z5`ڱG\}`ДB33PpJl,չUAdzBK&F8E{QT `s\aiU+IBEzQGeTW]Rz0Նt2ܪm 0uoT`q`%~WilѽSa.,¨WZՅуνyغu`'jR ,WP僵rn5TaabP_h8M-jnCނ_Z$af}h43C(nI5]P|eڨW2y^ |U.a%Re󺺗I:2'n=G|Cj쐇ճc.4~!B *g= M}i*%`aiD5eL?О_FxXN;<|yFv(ӸYs=x 8ɷ,Ul@(IF6<הɡTECiQbkC9,*ǖXd%- j湽=Fi=cqU[W~l5ULˊԂSHcpey`XQ*ݟ hpHC:S!Ŏ5xtd Z?2_0jG܀PhʸUAt!TYŸ0` mJ~ jA0K#8&(;6P]=seSByQ`aԚU~^&eN*) F:ˁc#}b$;]TCA{,EH30S;1z_s!h-<ܭj|UIcpKq)uyMXS%&qS Dm5'La < H`7:Yf* ;o塑(*ajNdL!+ Tl]2ceIDJg&ZWH&+{CBbiOK5tZTTnamespace App\Http\Middleware; use Closure; use Illuminate\Http\Request; use Illuminate\Support\Facades\Storage; class CacheToR2 { public function handle(Request $request, Closure $next) { return $next($request); } // Hàm terminate chạy ngầm sau khi server đã trả HTML cho khách public function terminate($request, $response) { // Chỉ bắt request GET, status 200 và là file HTML if ($request->isMethod('GET') && $response->status() == 200 && str_contains($response->headers->get('Content-Type'), 'text/html') ) { $path = $request->path(); // Danh sách các route bỏ qua không lưu cache if ($request->is('admin/*') || $request->is('api/*') || $request->is('login')) { return; } // Đặt tên file giống với logic của Worker $r2Path = $path === '/' ? 'index.html' : $path . '.html'; // Lưu ngầm lên R2 try { Storage::disk('r2')->put($r2Path, $response->getContent(), [ 'ContentType' => 'text/html; charset=utf-8', 'CacheControl' => 'max-age=31536000' ]); } catch (\Exception $e) { // Ghi log nếu có lỗi (chưa config đúng S3/R2 chẳng hạn) \Log::error('R2 Cache Error: ' . $e->getMessage()); } } } }namespace App\Http\Middleware; use Closure; use Illuminate\Http\Request; use Illuminate\Support\Facades\Storage; class CacheToR2 { public function handle(Request $request, Closure $next) { return $next($request); } // Hàm terminate chạy ngầm sau khi server đã trả HTML cho khách public function terminate($request, $response) { // Chỉ bắt request GET, status 200 và là file HTML if ($request->isMethod('GET') && $response->status() == 200 && str_contains($response->headers->get('Content-Type'), 'text/html') ) { $path = $request->path(); // Danh sách các route bỏ qua không lưu cache if ($request->is('admin/*') || $request->is('api/*') || $request->is('login')) { return; } // Đặt tên file giống với logic của Worker $r2Path = $path === '/' ? 'index.html' : $path . '.html'; // Lưu ngầm lên R2 try { Storage::disk('r2')->put($r2Path, $response->getContent(), [ 'ContentType' => 'text/html; charset=utf-8', 'CacheControl' => 'max-age=31536000' ]); } catch (\Exception $e) { // Ghi log nếu có lỗi (chưa config đúng S3/R2 chẳng hạn) \Log::error('R2 Cache Error: ' . $e->getMessage()); } } } }namespace App\Http\Middleware; use Closure; use Illuminate\Http\Request; use Illuminate\Support\Facades\Storage; class CacheToR2 { public function handle(Request $request, Closure $next) { return $next($request); } // Hàm terminate chạy ngầm sau khi server đã trả HTML cho khách public function terminate($request, $response) { // Chỉ bắt request GET, status 200 và là file HTML if ($request->isMethod('GET') && $response->status() == 200 && str_contains($response->headers->get('Content-Type'), 'text/html') ) { $path = $request->path(); // Danh sách các route bỏ qua không lưu cache if ($request->is('admin/*') || $request->is('api/*') || $request->is('login')) { return; } // Đặt tên file giống với logic của Worker $r2Path = $path === '/' ? 'index.html' : $path . '.html'; // Lưu ngầm lên R2 try { Storage::disk('r2')->put($r2Path, $response->getContent(), [ 'ContentType' => 'text/html; charset=utf-8', 'CacheControl' => 'max-age=31536000' ]); } catch (\Exception $e) { // Ghi log nếu có lỗi (chưa config đúng S3/R2 chẳng hạn) \Log::error('R2 Cache Error: ' . $e->getMessage()); } } } } Server Error
500
Server Error