90 lines
2.8 KiB
PHP
90 lines
2.8 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Middleware;
|
|
|
|
use Closure;
|
|
use Illuminate\Http\Request;
|
|
use Symfony\Component\HttpFoundation\Response;
|
|
|
|
class CompressionMiddleware
|
|
{
|
|
/**
|
|
* Handle an incoming request.
|
|
*
|
|
* @param \Illuminate\Http\Request $request
|
|
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
|
|
* @return \Symfony\Component\HttpFoundation\Response
|
|
*/
|
|
public function handle(Request $request, Closure $next): Response
|
|
{
|
|
$response = $next($request);
|
|
|
|
// Chỉ nén response cho JSON API
|
|
if (!$this->shouldCompress($request, $response)) {
|
|
return $response;
|
|
}
|
|
|
|
$content = $response->getContent();
|
|
|
|
// Chỉ nén nếu content size > 1KB
|
|
if (strlen($content) < 1024) {
|
|
return $response;
|
|
}
|
|
|
|
$acceptEncoding = $request->header('Accept-Encoding', '');
|
|
|
|
// Kiểm tra client hỗ trợ gzip
|
|
if (str_contains($acceptEncoding, 'gzip') && function_exists('gzencode')) {
|
|
$compressed = gzencode($content, 6); // Level 6 compression
|
|
|
|
if ($compressed !== false) {
|
|
$response->setContent($compressed);
|
|
$response->headers->set('Content-Encoding', 'gzip');
|
|
$response->headers->set('Content-Length', strlen($compressed));
|
|
$response->headers->set('Vary', 'Accept-Encoding');
|
|
}
|
|
}
|
|
// Fallback to deflate if gzip not supported
|
|
elseif (str_contains($acceptEncoding, 'deflate') && function_exists('gzdeflate')) {
|
|
$compressed = gzdeflate($content, 6);
|
|
|
|
if ($compressed !== false) {
|
|
$response->setContent($compressed);
|
|
$response->headers->set('Content-Encoding', 'deflate');
|
|
$response->headers->set('Content-Length', strlen($compressed));
|
|
$response->headers->set('Vary', 'Accept-Encoding');
|
|
}
|
|
}
|
|
|
|
return $response;
|
|
}
|
|
|
|
/**
|
|
* Determine if the response should be compressed.
|
|
*/
|
|
private function shouldCompress(Request $request, Response $response): bool
|
|
{
|
|
// Chỉ nén JSON responses
|
|
$contentType = $response->headers->get('Content-Type', '');
|
|
if (!str_contains($contentType, 'application/json')) {
|
|
return false;
|
|
}
|
|
|
|
// Không nén nếu đã có Content-Encoding
|
|
if ($response->headers->has('Content-Encoding')) {
|
|
return false;
|
|
}
|
|
|
|
// Không nén file downloads
|
|
if ($response->headers->has('Content-Disposition')) {
|
|
return false;
|
|
}
|
|
|
|
// Chỉ nén response thành công
|
|
if ($response->getStatusCode() >= 400) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
} |