Bỏ qua tới nội dung
Lỗi & sập trang

Lỗi "HTTP error" khi tải ảnh lên WordPress: Cây quyết định thật sự tìm ra nguyên nhân

Xác định nguyên nhân thật của lỗi HTTP khi upload ảnh trong WordPress chỉ bằng một lần kiểm tra, rồi sửa đúng nhánh: tường lửa, bộ nhớ PHP, post_max_size hay Imagick.

Đã đăng

“HTTP error” không phải là nguyên nhân. Đó là lời thú nhận của trình tải lên rằng nó đã gửi tệp của bạn tới máy chủ và nhận về một phản hồi mà nó không đọc được như một kết quả thành công — và có ít nhất sáu sự cố chẳng liên quan gì đến nhau lại cho ra đúng ba chữ giống hệt nhau. Đoán mò giữa sáu khả năng đó chính là lý do nhiều người mất cả buổi chiều nâng upload_max_filesize trên một trang mà vấn đề thật là một quy tắc tường lửa.

Lối ra nhanh nhất là một quan sát duy nhất chia sáu nguyên nhân thành hai nhóm, rồi một lần kiểm tra cho mỗi nhánh.

Trước hết: đọc phản hồi thật

Mở công cụ dành cho nhà phát triển của trình duyệt, vào tab Network, rồi tải tệp lên lần nữa. Để ý request tới async-upload.php. Thứ trả về chính là chẩn đoán của bạn.

Bạn nhìn thấy gìNó nghĩa là gìSang nhánh
403 hoặc 406, phần thân là HTMLTường lửa hoặc mod_security đã từ chối requestNhánh A
500, hoặc phản hồi rỗng, hoặc phần thân bị cắt cụtPHP sập hoặc hết bộ nhớ giữa chừngNhánh B
413Phần thân request vượt quá một giới hạn của máy chủNhánh C
200, nhưng phần thân không phải JSON sạchMột plugin hoặc theme đã in ra nội dung trước phản hồiNhánh D
Request không bao giờ xong / hết thời gian chờGiới hạn thời gian thực thi, thường gặp với tệp lớnNhánh B

Chỉ một lần nhìn đó là bạn loại được phần lớn lời khuyên đang trôi nổi trên mạng. Nếu không dùng được công cụ trình duyệt, hãy bật ghi log trong wp-config.php trước:

define( 'WP_DEBUG', true );
define( 'WP_DEBUG_LOG', true );
define( 'WP_DEBUG_DISPLAY', false );

Lặp lại thao tác tải lên, rồi đọc wp-content/debug.log. Một dòng lỗi nghiêm trọng sẽ gọi tên nhánh một cách thẳng thừng. Nếu dòng đó khó hiểu, hãy dán vào công cụ giải mã log lỗi — nó ánh xạ các dấu hiệu lỗi nghiêm trọng phổ biến sang thứ thật sự đã hỏng.

Nhánh A — tường lửa hoặc quy tắc mod_security

Mã 403 kèm một trang HTML trong phần thân nghĩa là request chưa từng chạm tới WordPress. Thứ gì đó đứng phía trước — mod_security, Cloudflare, Wordfence, Sucuri, hay chính bộ quy tắc của nhà cung cấp hosting — đã đánh giá rằng POST này trông có vẻ độc hại.

Cách kiểm tra: tạm tắt mọi plugin bảo mật rồi tải lên lại. Nếu chẳng thay đổi gì, quy tắc nằm ở mức máy chủ, và bạn cần nhà cung cấp hosting xem log kiểm toán mod_security tại đúng thời điểm lượt tải lên thất bại. Họ có thể đưa ID quy tắc cụ thể đó vào danh sách cho phép.

Hãy sòng phẳng với chính mình về những lời khuyên bạn sẽ gặp ở đây. Các đoạn mã bảo bạn dán thứ này vào .htaccess:

SecFilterEngine Off
SecFilterScanPOST Off

nhắm tới mod_security 1.x, thứ gần như đã tuyệt chủng. Trên máy chủ hiện đại, các chỉ thị đó hoặc chẳng làm gì, hoặc ném ra lỗi 500 khiến trang tệ hơn. mod_security hiện đại dùng SecRuleEngine, và đa số hosting quản lý đều chặn việc ghi đè nó theo từng thư mục. Hãy hỏi nhà cung cấp hosting, đừng dán mã.

Nhánh B — giới hạn bộ nhớ hoặc thời gian thực thi của PHP

Đây là nhánh phổ biến nhất và cũng là nhánh có dấu hiệu rõ ràng nhất: lỗi lúc có lúc không. Cùng một tệp đến lần thử thứ ba thì tải được, hoặc một tấm ảnh 2MB thì lỗi trong khi một tệp PDF 6MB lại trôi qua ngon lành. Giới hạn cấu hình cứng thì lần nào cũng lỗi y hệt. Lỗi do bộ nhớ thì không, vì lượng bộ nhớ còn trống phụ thuộc vào việc máy chủ đang làm gì khác.

Vì sao lại đặc biệt là ảnh: WordPress không chỉ lưu tệp, nó còn giải nén ảnh thành điểm ảnh thô để tạo mọi kích thước trung gian — medium_large, mọi kích thước đăng ký bằng add_image_size, woocommerce_thumbnail nếu bạn chạy cửa hàng, cộng thêm một bản -scaled nếu ảnh vượt big_image_size_threshold. Một ảnh JPEG 12 megapixel chỉ nặng vài MB trên đĩa nhưng chiếm khoảng 48MB trong bộ nhớ, chưa tính vùng đệm để thay đổi kích thước. Giới hạn 128MB biến mất rất nhanh.

Nâng nó trong wp-config.php, phía trên dòng “stop editing”:

define( 'WP_MEMORY_LIMIT', '256M' );
define( 'WP_MAX_MEMORY_LIMIT', '512M' );

Cái giá thật sự: WP_MEMORY_LIMIT không thể vượt quá mức PHP cho phép. Nếu nhà cung cấp hosting chặn memory_limit ở 128M thì hằng này chỉ để trang trí. Hãy xem giá trị thật ở Công cụ → Sức khỏe trang web → Thông tin → Máy chủ, chứ đừng tin vào con số bạn vừa viết. Nếu giới hạn của chính PHP mới là trần, chỉ nhà cung cấp hosting mới nâng được.

Nhánh C — giới hạn kích thước tệp và kích thước POST

Xem con số thực tế tại Công cụ → Sức khỏe trang web → Thông tin → Xử lý phương tiện. Có hai thiết lập quan trọng mà người ta chỉ đổi mỗi một cái:

  • upload_max_filesize — trần cho một tệp đơn lẻ.
  • post_max_size — trần cho toàn bộ phần thân request.

Nếu cả gói POST vượt post_max_size, PHP vứt bỏ request trước khi WordPress chạy bất kỳ dòng mã nào. Chẳng có gì tồn tại để trả về, nên trình tải lên nhận một phản hồi không đọc được và báo “HTTP error”. post_max_size luôn phải lớn hơn upload_max_filesize một khoảng thoải mái.

Một điểm đáng biết: khi một tệp chỉ vượt riêng upload_max_filesize, trình tải lên thường bắt được ngay trong trình duyệt và báo rằng tệp vượt quá dung lượng tối đa — một thông báo rõ ràng hơn hẳn. Vậy nên một dòng “HTTP error” trơ trọi thường chỉ về post_max_size hoặc về Nhánh B nhiều hơn là về thiết lập mà ai cũng nâng đầu tiên.

Đổi chúng ở đâu thì tùy nền tảng của bạn. Trên Apache dùng mod_php, .htaccess có tác dụng:

php_value upload_max_filesize 64M
php_value post_max_size 128M

Trên PHP-FPM, LiteSpeed hay NGINX — tức phần lớn hosting hiện đại — những dòng đó vô tác dụng, và còn có thể ném ra lỗi 500. Hãy dùng bảng thiết lập PHP của nhà cung cấp hosting hoặc một tệp .user.ini. NGINX còn áp giới hạn riêng của nó là client_max_body_size, và chỉ nhà cung cấp hosting mới nâng được.

Nhánh D — thư viện xử lý ảnh (Imagick so với GD)

WordPress ưu tiên ImageMagick khi phần mở rộng PHP có sẵn, và lùi về GD nếu không. Trên hosting chia sẻ, ImageMagick rất hay là thủ phạm: tệp cấu hình chính sách của nó siết bộ nhớ, dung lượng đĩa và diện tích ảnh cho mỗi thao tác, và khi một lần thay đổi kích thước chạm phải một trong các giới hạn đó thì tiến trình chết mà không để lại thông báo nào hữu ích. Bạn thường gặp cảnh này với ảnh lớn trong khi ảnh nhỏ vẫn ổn — nhìn thì giống Nhánh B nhưng không phải.

Ép dùng GD để kiểm chứng giả thuyết:

add_filter( 'wp_image_editors', function ( $editors ) {
    return array( 'WP_Image_Editor_GD' );
} );

Đặt đoạn đó vào functions.php hoặc một mu-plugin nhỏ, thử tải lên lại, rồi gỡ ra nếu không có gì thay đổi.

Đánh đổi thật lòng: GD không hẳn là tốt hơn. Nó giữ toàn bộ ảnh bitmap chưa nén trong bộ nhớ của PHP, nên với tệp rất lớn nó có thể chạm memory_limit ở chỗ mà ImageMagick — vốn hoạt động một phần bên ngoài vùng cấp phát của PHP — vẫn làm được. Chuyển đổi có thể chỉ là đổi lỗi này lấy lỗi khác. Hãy xem nó là công cụ chẩn đoán trước, cách sửa sau.

Nhánh E — quyền của thư mục uploads

Hiếm gặp trên hosting quản lý, nhưng rất phổ biến ngay sau một lần chuyển trang hoặc chuyển máy chủ thủ công. Nếu wp-content/uploads không cho người dùng máy chủ web ghi, hoặc một thư mục con năm/tháng vừa được tạo lại thừa hưởng sai chủ sở hữu, thao tác ghi sẽ thất bại.

ls -ld wp-content/uploads
ls -ld wp-content/uploads/2026/07

Thư mục thường nên ở mức 755 và thuộc về người dùng mà PHP đang chạy dưới danh nghĩa. Đừng đặt 777 chỉ vì một diễn đàn bảo thế — nó chữa triệu chứng bằng cách cho mọi tài khoản trên máy chủ ghi vào thư mục đó, và trên hosting chia sẻ thì đây là một lỗ hổng thực sự.

Nhánh F — tên tệp

Đây là lần kiểm tra rẻ nhất danh sách, nên hãy làm sớm dù nó ít khả năng nhất. Đổi tên tệp thành chữ thường, số và dấu gạch ngang — không dấu tiếng Việt, không dấu nháy đơn, không dấu và, không #, không ký tự ngoài bảng Latinh — rồi tải lên lại. Ký tự đặc biệt đôi khi kích hoạt một quy tắc bảo mật hoặc gãy trên hệ thống tệp có bảng mã không khớp. Mười giây để loại trừ.

Những việc không nên làm

Đừng bắt đầu bằng cách tắt hết plugin. Việc đó gây xáo trộn mà chỉ kiểm tra được Nhánh A và Nhánh D. Phản hồi mạng cho bạn biết nhiều hơn chỉ trong năm giây.

Đừng thêm một dòng handler tùy tiện vào .htaccess. Các đoạn mã đang lan truyền có chỉ thị SetHandler hoặc AddHandler được viết cho cấu hình PHP của một nhà cung cấp cụ thể. Đặt nhầm nền tảng là cả trang sập với lỗi 500.

Đừng coi “thử lại thì được” là đã sửa xong. Thành công lúc được lúc không chính là chữ ký của Nhánh B, và nó sẽ quay lại ngay khi máy chủ bận hoặc có ai đó tải lên tệp lớn hơn.

Vẫn bế tắc?

Nếu phản hồi là mã 200 sạch sẽ với JSON hợp lệ mà việc tải lên vẫn hỏng, thì chỗ gãy nằm sau khi tệp đã lên tới nơi — thường là một plugin móc vào chuỗi xử lý tệp đính kèm và ném lỗi nghiêm trọng, hoặc một plugin tối ưu ảnh gửi request riêng tới một dịch vụ bên ngoài rồi hết thời gian chờ. Hãy bật WP_DEBUG_LOG, lặp lại thao tác, rồi đưa lỗi nghiêm trọng thu được qua công cụ giải mã log lỗi để biết tệp nào và hook nào thật sự chịu trách nhiệm.

FAQ

Câu hỏi

Lỗi HTTP error khi tải ảnh lên WordPress nghĩa là gì?

Nghĩa là trình tải lên trong trình duyệt đã gửi tệp của bạn tới máy chủ và nhận về một thứ mà nó không đọc được như một phản hồi thành công hợp lệ. Dòng thông báo mô tả triệu chứng, không phải nguyên nhân. Một tiến trình PHP bị sập, một lần chặn của tường lửa, mã 403 hay một phản hồi rỗng đều cho ra đúng ba chữ giống hệt nhau.

Vì sao cùng một ảnh lúc tải lên được, lúc lại lỗi?

Lỗi lúc được lúc không hầu như luôn chỉ về việc cạn bộ nhớ hoặc CPU chứ không phải một giới hạn cấu hình. Việc thay đổi kích thước một tấm ảnh lớn cần một lượng bộ nhớ dồn dập, và trên hosting chia sẻ thì lượng bộ nhớ còn trống thay đổi theo tải máy chủ. Một giới hạn cứng như post_max_size sẽ lỗi y hệt nhau trong mọi lần.

Chuyển WordPress từ Imagick sang GD có sửa được lỗi HTTP không?

Đôi khi có, và chỉ đúng cho một nhánh cụ thể. ImageMagick trên hosting chia sẻ thường bị siết bởi tệp chính sách hoặc bởi hạn mức tài nguyên thấp, nên nó thất bại ở chỗ GD làm được. Tuy nhiên GD tốn nhiều bộ nhớ hơn với tệp rất lớn, nên việc chuyển đổi có thể làm các lỗi do bộ nhớ trầm trọng thêm chứ không đỡ hơn.

Làm sao biết tường lửa của nhà cung cấp hosting đang chặn lượt tải lên?

Mở công cụ mạng của trình duyệt, tải tệp lên, rồi xem mã trạng thái trả về cho async-upload.php. Mã 403 hoặc 406 kèm phần thân là HTML nghĩa là một tường lửa ứng dụng web hoặc một quy tắc mod_security đã từ chối request. Mã 500 hoặc phản hồi rỗng thì lại chỉ về việc PHP bị sập.

Tăng upload_max_filesize có sửa được lỗi HTTP không?

Chỉ khi tệp thực sự vượt quá giới hạn của bạn, và post_max_size thường mới là thứ quan trọng hơn. Nếu toàn bộ phần thân request lớn hơn post_max_size, PHP sẽ vứt bỏ nó trước khi WordPress kịp chạy và trình tải lên không nhận lại được gì. Nâng cái này mà quên cái kia thì lỗi vẫn nguyên như cũ.

Tên tệp có thể gây ra lỗi HTTP trong WordPress không?

Có, dù đây là nhánh hiếm gặp nhất. Ký tự có dấu, dấu nháy đơn, dấu và, cùng các hệ chữ không phải Latinh có thể kích hoạt một quy tắc bảo mật hoặc làm hỏng đường dẫn trên hệ thống tệp có bảng mã không khớp. Đổi tên thành chữ thường, số và dấu gạch ngang chẳng tốn gì mà loại trừ được nhánh này trong khoảng mười giây.