Về việc tích hợp Google Pay vào Website
Bạn hiểu là trong quá trình thanh toán thì thông tin thẻ sẽ được chuyển đổi thành một token an toàn (tokenization). Token này sau đó có thể được sử dụng để thực hiện giao dịch mà không cần tiết lộ thông tin thẻ thực. Trong API Doc về phần Payment Method của Google Pay cũng có đề cập, bạn sẽ có hai cách thực hiện tokenization.
PAYMENT GATEWAY
: Là phương thức mà thông tin thanh toán được gửi đến một cổng thanh toán bên thứ ba để xử lý. Khi sử dụng phương thức này, bạn cần cung cấp thông tin về cổng thanh toán của mình, bao gồm tên của cổng thanh toán và các thông tin xác thực cần thiết. Google Pay có để ví dụ như này:
"tokenizationSpecification": {
"type": "PAYMENT_GATEWAY",
"parameters": {
"gateway": "example",
"gatewayMerchantId": "exampleGatewayMerchantId"
}
}
DIRECT
: Là phương thức mà thông tin thanh toán được mã hóa và trực tiếp gửi từ ứng dụng hoặc trang web của bạn đến máy chủ của bạn mà không qua bất kỳ cổng thanh toán bên thứ ba nào. Điều này đòi hỏi bạn phải có khả năng xử lý thông tin thanh toán an toàn và tuân thủ các quy định về bảo mật dữ liệu, như PCI DSS. Google Pay có để ví dụ như này:
"tokenizationSpecification": {
"type": "DIRECT",
"parameters": {
"protocolVersion": "ECv2",
"publicKey": "BOdoXP1aiNp.....kh3JUhiSZKHYF2Y="
}
}
Lấy dữ liệu HS code từ trang web
@wiliamfeng Viết script gọi thẳng API của họ luôn bạn ơi. Crawl theo DOM làm gì. Mẫu endpoint này để lấy mấy thằng con thì phải. Bạn ngâm cứu theo hướng này xem:
curl 'https://vntr.moit.gov.vn/vi/api/v1/commodity/child'
--data-raw 'v=&id=05&c_level=-1&locale=vi&search_id='
Share link qua Zalo
@wiliamfeng Để thêm nút "Chia sẻ" của Zalo bạn làm theo các bước dưới đây nhé:
- Bước 1: Chèn Zalo SDK: https://sp.zalo.me/plugins/sdk.js
- Bước 2: Khai báo Share Widget trong HTML: https://developers.zalo.me/docs/social/share
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Zalo Share Widget - Demo</title>
</head>
<body>
<!-- Step 2: Declare share button -->
<div
class="zalo-share-button"
data-oaid="2113601353031993630"
data-href="https://devsuccess101.com"
data-share-type="4"
data-color="blue"
></div>
<!-- Step 1: Inject Zalo SDK for JavaScript -->
<script async src="https://sp.zalo.me/plugins/sdk.js"></script>
</body>
</html>
build 1 dự án react thuần thành 1 file css và 1 file js
Trường hợp này bạn cần nhúng 2 thư viện là react
và react-dom
vào trong trong trang HTML của bạn nhé. Mình không khuyến nghị bạn triển khai theo hướng này trừ khi bạn đang maintain một website rất cũ và bắt buộc phải làm như vậy.
Cách nhúng hai thư viện trên vào trang thì bạn dùng link CDN trực tiếp, được cung cấp bởi CDNJS. Bạn sẽ thấy chỉ việc tạo mỗi một thẻ div
đơn sơ trong component Hello
thôi mà đã dài dòng văn tự rồi.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>React without JSX</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.3.1/umd/react.production.min.js" integrity="sha512-QVs8Lo43F9lSuBykadDb0oSXDL/BbZ588urWVCRwSIoewQv/Ewg1f84mK3U790bZ0FfhFa1YSQUmIhG+pIRKeg==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.3.1/umd/react-dom.production.min.js" integrity="sha512-6a1107rTlA4gYpgHAqbwLAtxmWipBdJFcq8y5S/aTge3Bp+VAklABm2LO+Kg51vOWR9JMZq1Ovjl5tpluNpTeQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
</head>
<body>
<div id="root">Loading...</div>
<script>
class Hello extends React.Component {
render() {
return React.createElement('div', null, `Hello ${this.props.toWhat}`);
}
}
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(React.createElement(Hello, {toWhat: 'World'}, null));
</script>
</body>
</html>
Để ngắn hơn thì bạn lại dùng JSX và sử dụng Babel để transform JSX nhé. Vẫn cài thêm Babel bằng CDN link tương tự với react
. Do transform ngay tại thời điểm runtime trên browser nên tốc độ rendering của browser sẽ bị giảm đi.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>React with JSX</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.3.1/umd/react.production.min.js" integrity="sha512-QVs8Lo43F9lSuBykadDb0oSXDL/BbZ588urWVCRwSIoewQv/Ewg1f84mK3U790bZ0FfhFa1YSQUmIhG+pIRKeg==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.3.1/umd/react-dom.production.min.js" integrity="sha512-6a1107rTlA4gYpgHAqbwLAtxmWipBdJFcq8y5S/aTge3Bp+VAklABm2LO+Kg51vOWR9JMZq1Ovjl5tpluNpTeQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<!-- Add Babel -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/7.24.5/babel.min.js" integrity="sha512-F62mvp9bPPLjVOpNlD+9erbo9KBRQKkLittcNub5D2o8WfgV9nrJR/0hKc1OUY3LNwlo671inEZzCjnLJz62nw==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
</head>
<body>
<div id="root">Loading...</div>
<!-- Using JSX with Babel -->
<script type="text/babel" data-presets="react">
class Hello extends React.Component {
render() {
return <div>Hello {this.props.toWhat}</div>;
}
}
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<Hello toWhat="World" />);
</script>
</body>
</html>
micro service
Authentication và authorization là một trong số các generic domain của một hệ thống. Trong microservices, người ta cũng thường tách biệt authentication và authorization ra tầng API Gateway. Khi đó, các microservices không phải xử lý authentication nữa mà chỉ cần tập trung vào giải quyết các bài toán nghiệp vụ chính của doanh nghiệp mà thôi.
api - laravel
Do là hai project riêng biệt nên B muốn dùng chung được access token của A thì có lẽ bạn cũng sẽ cần phải mang APP_KEY của A sang dùng cho B cũng như implement thêm cơ chế authentication/authorization y hệt như trên A. -> Bạn có thể đóng gói hết code cho việc authentication của A thành một composer package rồi cài sang cho B.
Ngoài ra cũng có thể ứng dụng các phương án khác như:
- Tách phần authentication / authorization của A ra xử lý tại tầng API Gateway. A và B cùng đứng sau API Gateway thì không cần phải xử lý lại authentication nữa.
- Cũng có thể dùng kiểu tạo middleware trên B gọi ngược sang A để lấy thông tin. Tuy nhiên điểm hạn chế của nó là B sẽ bị phụ thuộc vào A. Cùng với đó là B cũng cần triển khai trên chung private network vì nếu từ B mà gọi sang A qua public domain thì coi như bỏ vì response time sẽ tăng lên rất nhiều.
- SSO, Oauth2, OIDC...
Reset select option khi click back history
Vấn đề em đang gặp phải là do trình duyệt lưu trạng thái của trang web như dữ liệu của các thẻ input, vị trí cuộn, trạng thái của các phần tử DOM... Các dữ liệu này được restore khi nhấn nút Back.
Anh nghĩ em hãy thử mấy cách sau:
- Trang nào ko muốn cache thì server thêm header yêu cầu ko no-cache chặng hạn
- Dùng JavaScript bắt sự kiện tải trang rồi thực hiện reset về default value
- Không render ssr cái field input đó, mà thử render dưới client side xem?
Nhưng mà anh nghĩ là có thể nó lưu các trạng thái này vào memory hoặc đâu đó, nên cách 1 và 3 có thể không có tác dụng. Cách 2 thì bắt sự kiện pageshow như sau:
<form method="GET" url="/">
<input name="submitted" value="default" />
<button type="submit">Submit</button>
</form>
<script>
window.addEventListener('pageshow', () => {
const input = document.querySelector('input');
const url = new URL(location);
if (input && !url.searchParams.get('submitted')) {
input.value = 'default';
}
});
</script>
ZSH from BASH on WSL
Một vài câu lệnh của bạn ở đây là câu lệnh như nào ấy nhỉ? Nếu chúng là alias thì bạn cần khai báo các alias này trong file ~/.zshrc nữa thì khi dùng zsh mới nhận.
Còn nếu không phải alias mà lại không tương thích với ZSH thì bạn có thể thứ các cách sau:
- Nếu command dài -> tạo file
*.sh
để chạy - Hoặc nếu ngắn thì chạy bới bash bằng flag
-c
:
bash -c "echo Your Bash script"
- Hoặc là mở bash shell để chạy command, xong rồi lại exit ra ZSH:
bash
- Hoặc convert command đó sang cú pháp của ZSH
Đưa media từ rails assets vào trong file javascript
File của em đã được public đúng URL chưa? Anh đoán là chưa. Em đưa nó vào thư mục public nhé. http://localhost/assets/audio/drumsticks.mp3
Với cả, em dùng lệnh setInterval với this như kia sẽ lỗi đó. Vì this sẽ out of scope và còn không tồn tại. Em dùng kiểu này:
setInterval(this.beat.play.bind(this.beat), 1000)
Lối loop khi sử dụng setInterval
Khả năng lỗi do dòng này nè em:
this.timer = setInterval(this.beat.play(), (60 / this.bpm) * 1000)
Cái argument đầu tiên phải là một function
để nó thực thi trong mỗi lần lặp. Còn trong code kia thì tại dòng setInterval
cái hàm play
nó đã chạy luôn mất rồi. Em sửa lại kiểu như sau:
this.timer = setInterval(this.beat.play.bind(this.beat), (60 / this.bpm) * 1000);
// hoặc thế này:
this.timer = setInterval(() => this.beat.play(), (60 / this.bpm) * 1000);
https://developer.mozilla.org/en-US/docs/Web/API/setInterval
Khi triển khai ứng dụng Docker CI/CD gặp bug hotfix thì nên xử lý thế nào cho ấm êm cả nhà?
- Nếu là lỗi cực kỳ nghiêm trong thì bạn cần xử lý rollback về phiên bản cũ ngay. Bạn có thể lên CI retry lại step deploy trong bản build của lần release trước đó. Hoặc cũng có thực hiện thủ công bằng tay.
- Nếu lỗi không quá nghiêm trọng mà có thể fix nhanh được thì tạo PR hotfix merge đồng thời cho cả prod và môi trường kiểm thử staging.
Đa ngôn ngữ trong php
Thay vì sử dụng file js hoặc json, bạn hãy sử dụng file .php và require nó như code PHP bình thường. Như vậy phần translations sẽ là một phần của source code PHP. Bạn không phải lo lắng về vấn đề đọc file_get_content vì thường trên server sẽ cấu hình opcache.
Best way để upload 100k rows file excel vào database
Có nhiều hướng tiếp cận:
- Sử dụng JS để đọc file excel và hiển thị trực tiếp nội dung file trên browser. Khi hiển thị thì đồng thời thực hiện validate dữ liệu và báo lỗi luôn. Chỗ này có thể cho sửa trực tiếp dữ liệu ngay trên browser. Khi nhấn upload thì không gửi file lên server mà sẽ gửi dữ liệu theo từng batch, VD: Đọc một cục dữ liệu theo từng 5, 10, 50 rows để gửi lên server. Nếu server có lỗi thì trả về thông tin cần thiết cho browser như lỗi row nào, do đâu để browser hiển thị lại trên màn hình.
- Vẫn đọc file excel trên browser & validate + hiển thị lỗi luôn. Sau khi user fix hết lỗi thì cho upload file lên server.
- Upload file thẳng lên server:
- Server lưu lại file đồng thời cũng lưu một record vào database, kiểu như: File A, Status: Queued, Created Time, Completed Time.
- Đẩy một job
UploadExcelFile
vào queue. Bạn có thể dùng queue id để tạo channel web socket hiển thị kết quả xử lý realtime nếu cần. Job này có nhiệm vụ là thực hiện đọc dữ liệu từ file excel theo từng batch 100 rows /1 lần đọc (các lib thường có option này). Thực hiện validate từng row, cái nào hợp lệ thì lưu, cái nào lỗi thì có thể bắn về cho client qua web socket hoặc lưu lại ra file excel có cấu trúc tương tự. Job chạy xong thì cập nhật lại Status trong Database, Tên File kết quả các dòng lỗi nếu có.
Nhìn chung là có thể làm như trên hoặc phối kết hợp các cách trên hoặc cũng có thể thêm thắt các tùy biến khác sao cho phù hợp với tình hình, kiến trúc hệ thống và cả tiến độ dự án.
Build dự án ra file dist thì khi reload lại trang bị lỗi.
Nó bị lỗi khả năng là app bạn đang làm là SPA mà trên server bạn chỉ cấu hình routing cho duy nhất trang root /. Điều này sẽ lý giải cho việc:
- Khi bạn vào trang chủ bằng URL trên trình duyệt vẫn xem được.
- Bạn click vào link trang khác thì vẫn xem được. Việc chuyển trang trên browser thực chất chỉ là client-side navigation do Vue Router thực hiện. Do đó, nội dung bạn xem được là Vue App tạo ra, không phải kết quả từ server trả về.
Bạn cần cấu hình Rewrite URL cho Apache trên hosting để xem được nhé. Mà nếu app chỉ là SPA thì bạn nên upload lên Github Pages hoặc các dịch vụ cloud khác có lẽ sẽ đỡ tốn chi phí hơn là dùng hosting mà lại được dùng sẵn CDN từ các dịch vụ đó.
Hỏi về tối ưu messenger chat trong vuejs
Cần gì phải phức tạp thế, bạn copy thẳng cái script embed của facebook rồi chèn vào cuối trang ấy. Xong thêm attribute này cho phần embed chatbox để nó hiện mỗi icon message, hộp chat chỉ hiện khi người dùng click vào icon.
greeting_dialog_display = icon
<!-- Messenger Chat Plugin Code -->
<div id="fb-root"></div>
<div id="fb-customer-chat" class="fb-customerchat"></div>
<script>
var chatbox = document.getElementById('fb-customer-chat');
chatbox.setAttribute("page_id", "PAGE-ID");
chatbox.setAttribute("greeting_dialog_display", "icon");
</script>
<script>
window.fbAsyncInit = function() {
FB.init({
xfbml : true,
version : 'API-VERSION'
});
};
(function(d, s, id) {
var js, fjs = d.getElementsByTagName(s)[0];
if (d.getElementById(id)) return;
js = d.createElement(s); js.id = id;
js.src = 'https://connect.facebook.net/en_US/sdk/xfbml.customerchat.js';
fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'facebook-jssdk'));
</script>
ai giúp em lỗi terminal ảo ma này ở vscode
Bạn thử đổi shell sang dùng cmd/powershell xem có bị tình trạng tương tự nữa không?
Cách tạo deeplink để nhảy đến màn hình trên app?
Bạn có thể dùng Firebase Dynamic Links nhé. https://firebase.google.com/docs/dynamic-links
Kinh nghiệm xin duyệt project trên Google Console
Project trên Google Console thì có phải đợi Google review gì đó thì mới dùng được đâu nhỉ? Bạn cứ tạo project, tạo credentials rồi enable những bộ API bạn cần dùng là sử dụng được ngay mà.
viblo SEO for a blog
- Website của bạn cần có một trang sitemap trả về dạng XML chứa danh sách các trang trong website của bạn mà bạn muốn Google quét, cũng như là tần suất quét.
- Bạn gửi link trang sitemap cho Google Search Console, sau đó thì Google Bot sẽ đều đặn scan các trang trên website của bạn để tạo index cho các thông tin tìm kiếm. m.
- Trang sitemap có thể là một file sitemap.xml tĩnh, hoặc cũng có thể là nội dung XML được tự động tạo mới mỗi khi bạn đăng thêm bài viết mới.
Nội dung XML được follow theo hướng dẫn tại đây: https://developers.google.com/search/docs/crawling-indexing/sitemaps/build-sitemap
Làm cách nào để remove token của user trong localStorage nếu token hết hạn?
- Khi browser request lên server, server check thấy token hết hạn thì trả về response báo hết phiên đăng nhập. VD: Response 440 - Session Expired
- Dưới client, nếu nhận response về với status code là 440 sẽ hiểu là hết phiên đăng nhập thì tự xóa local storage.