Vấn đề phát sinh

Vấn đề phát sinh

nohu club tai game nổ hũ đổi thưởng,nhà cái uy tín bk8vie,tải tool hack tài xỉu 789 club miễn phí

Sao chép bài viết từ WeChat Official Account sang Summernote, hình ảnh chuyển đổi thành Base64

Ngày cập nhật: 20/07/2018 | Số lần xem: 13.474 | Phân loại: Phát triển frontend


Một khách hàng là công ty du lịch phản hồi rằng khi họ sao chép nội dung bài viết từ trang WeChat Official Account của mình và dán vào trình soạn thảo văn bản phong phú (rich text editor) của một ứng dụng mini WeChat (sử dụng Summernote), thì khi nhấn nút lưu lại sẽ gặp lỗi.

Theo log của Laravel, lỗi được báo là vượt quá độ dài của trường dữ liệu. Từ kinh nghiệm trước đây, điều này thường xảy ra khi có hình ảnh được mã hóa dưới dạng Base64. Trong khi đó, nếu chỉ dùng URL thông thường thì khó có khả năng vượt qua giới hạn của kiểu dữ liệu TEXT (có thể chứa đến 65.535 ký tự).

Khi đồng nghiệp kiểm tra, họ nhận thấy:

  • Nếu hình ảnh chưa tải xong, thì khi sao chép vào Summernote sẽ xuất hiện định dạng Base64.
  • Ngược lại, nếu hình ảnh đã được tải đầy đủ, thì đường dẫn hình ảnh là một URL thông thường.

Điều này dường như không hợp lý.


Quá trình tìm nguyên nhân

Tôi đã kiểm tra mã HTML của bài viết trên WeChat Official Account và phát hiện đoạn code sau:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
<img class="img_loading" 
  data-ratio="0.75"
  data-s="300,640" 
  data-src=" 
  data-type="jpeg" 
  data-w="600" 
  width="auto" 
  _width="auto"            
  src="data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQImWNgYGBgAAAABQABh6FO1AAAAABJRU5ErkJggg==" 
  style="margin: 0px; padding: 0px; max-width: 100%; background-color: rgb(238, 237, 235); border-width: 1px; border-style: solid; border-color: rgb(238, 237, 235); background-size: 22px; background-position: center center; background-repeat: no-repeat; background-image: url("data:image/gif;base64,R0lGODlhPAA8APYAAJeXl56enp+fn6Cxxxxxxxxxx SO SO LONG xxxxxx

Nhận xét từ đoạn mã trên:

  1. Thuộc tính data-src mới là địa chỉ thật của hình ảnh.
  2. Khi có class img_loading, thuộc tính src chứa một hình ảnh GIF Base64 nhỏ biểu thị trạng thái đang tải.
  3. Tuy nhiên, background-image cũng chứa một Base64 — nhưng thực tế chỉ là một hình ảnh loading đơn giản.

Sau khi sử dụng công cụ Base64 to Image Converter để giải mã, tôi xác nhận rằng background-image chỉ là một hình ảnh GIF loading bình thường, trong khi src ban đầu là một Base64 rỗng nhằm tránh lỗi hiển thị do thiếu giá trị.

Từ đây, tôi kết luận rằng không phải hình ảnh gốc nào cũng bị chuyển thành Base64, mà chỉ là hình ảnh “đang tải”.


Giải pháp đề xuất

Để xử lý vấn đề này, ta cần thêm một hook vào sự kiện paste của Summernote, giúp thay thế các thuộc tính hình ảnh theo đúng logic.

Ngoài ra, nên thêm chức năng đếm số lượng ký tự và giới hạn độ dài để tránh vượt quá giới hạn của cơ sở dữ liệu.


Cách cài đặt hook onPaste cho Summernote

Tham khảo tài liệu tại:

Dưới đây là đoạn code minh họa:

1
2
3
4
5
6
7
$('#summernote').summernote({
  callbacks: {
    onPaste: function(e) {
      console.log('Sự kiện paste đã được kích hoạt');
    }
  }
});

Sau khi thay thế, hình ảnh vẫn hiển thị dòng chữ “Hình ảnh này đến từ nền tảng WeChat Public, không được phép sử dụng trái phép.”

Tại sao những hình ảnh đã tải xong lại hiển thị bình thường?

Dưới đây là hai ví dụ:

Hình ảnh hiển thị bình thường:

1
<img class="" data-ratio="0.75" data-s="300,640" data-src=" data-type="jpeg" data-w="600" width="auto" _width="auto" src=" data-fail="0" style="margin: 0px; padding: 0px; max-width: 100%; height: auto !important; word-wrap: break-word !important; visibility: visible !important; width: auto !important;">

Hình ảnh bị coi là “đạo nhái”:

1
<img class="img_loading" data-ratio="0.6171875" data-s="300,640" data-src=" data-type="jpeg" data-w="640" width="auto" _width="auto" src=" style="margin: 0px; padding: 0px; max-width: 100%; background-color: rgb(238, 237, 235); border-width: 1px; border-style: solid; border-color: rgb(238, 237, 235); background-size: 22px; background-position: center center; background-repeat: no-repeat; height: 395px !important; word-wrap: break-word !important; visibility: visible !important; width: 640px !important;">

So sánh hai đoạn code, ta thấy phần src có sự khác biệt ở:

1
&tp=webp&wxfrom=5&wx_lazy=1

Đây là một hiệu ứng quan sát sai lầm, vì hình ảnh đã được cache trong trình duyệt khi bạn truy cập trang WeChat trước đó. Sau khi xóa cache, hình ảnh vẫn không hiển thị.

Trên nền tảng ứng dụng mini WeChat, tất cả các hình ảnh CDN của Tencent đều không hiển thị, trừ khi người dùng click để xem toàn màn hình.


Sử dụng CDN cá nhân thay vì CDN WeChat

Sau khi cân nhắc kỹ lưỡng, tôi cho rằng việc sử dụng CDN riêng sẽ an toàn và ổn định hơn nhiều:

  • Việc dùng CDN WeChat làm tăng độ phức tạp trong phát triển frontend.
  • Không thể chắc chắn rằng CDN này sẽ còn hoạt động lâu dài.
  • Có nguy cơ cao hình ảnh bị xóa hoặc không tồn tại nữa bất kỳ lúc nào.

Vì vậy, giải pháp được áp dụng là:

  1. Lấy toàn bộ các đường dẫn hình ảnh từ CDN WeChat.
  2. Gỡ bỏ các thuộc tính Base64.
  3. Tải về nguồn gốc hình ảnh, upload lên CDN riêng (ví dụ Qiniu).
  4. Thay thế bằng đường dẫn CDN mới.

Nguồn gốc Base64 là từ đâu?

Phần Base64 loading được lấy từ file CSS sau:

1
var article_improve_combo_css = "//res.wx.qq.com/mmbizwap/en_US/htmledition/style/page/appmsg/page_mp_article_improve_combo3a7ab9.css";

Và được tải về thông qua JavaScript.


Đoạn code xử lý trong Summernote

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
onPaste: function(e) {
  var sn = this;
  // Dùng setTimeout để đảm bảo dữ liệu đã được cập nhật
  setTimeout(function () {
    $(e.currentTarget).find('img[data-src]').each(function() {
      var that = this;
      var img_src = $(this).data("src");
      if (img_src.indexOf('qpic.cn') == -1) {
        return;
      }
      // Gửi yêu cầu upload hình ảnh lên backend
      $.ajax({
        type: "POST",
        url: "/upload_xxx",
        data: {
          wx_image: img_src
        },
        success: function(data) {
          if (data.err_code == 0) {
            $(that).replaceWith(function() {
              return $('<img src="' + data.data + '">');
            });
            $(sn).summernote('triggerEvent', 'change');
          } else {
            alert("Lỗi khi upload hình ảnh");
          }
        }
      });
    });
  }, 100);
}

Hy vọng với bài viết này, bạn đã hiểu rõ nguyên nhân hình ảnh bị chuyển thành Base64 khi sao chép từ WeChat Official Account sang Summernote, và cách xử lý linh hoạt để tránh lỗi về mặt dữ liệu. Chúc bạn thành công trong quá trình phát triển dự án!

Licensed under CC BY-NC-SA 4.0
Built with Hugo
Theme Stack thiết kế bởi Jimmy