แอปพลิเคชันการส่งข้อความแบบทันทีรวมถึงเซิร์ฟเวอร์การจัดการและไคลเอนต์
มันได้รับการปรับใช้และเปิดตัวยินดีต้อนรับสู่การสัมผัสกับลูกค้าและฝ่ายบริหาร
โปรดอย่าเปลี่ยนบทบาทเริ่มต้นและการอนุญาตตามต้องการ โปรดรู้สึกถึงความรักเล็กน้อยและอย่าสร้างชื่อที่ไม่มีอารยธรรม
การใช้เฟรมเวิร์กไข่ด้านเซิร์ฟเวอร์ของบริการ IM
นับตั้งแต่การพัฒนาอินเทอร์เน็ตบนมือถือบริการส่งข้อความโต้ตอบแบบทันทีนำโดย WeChat ได้ถูกรวมเข้ากับทุกมุมของชีวิตของเราและยังมีบทบาทสำคัญในธุรกิจของ บริษัท บริษัท ของเราใช้บริการส่งข้อความโต้ตอบแบบทันที แต่ความต้องการที่กำหนดเองหลายแห่งไม่สามารถทำได้ ดังนั้นจึงมีการตัดสินใจที่จะพัฒนา Microservice การส่งข้อความโต้ตอบแบบทันทีที่ตรงกับความต้องการที่กำหนดเองภายใน
socket.io Framework ถูกนำมาใช้เพราะแบ็กเอนด์สั้นของผู้คนในเวลานั้น หลังจากอ่านตัวอย่างบางส่วนฉันคิดว่ามันสะดวกในการใช้งานและรองรับบนแพลตฟอร์มทั้งหมด ดังนั้น Microservice นี้จึงถูกนำไปใช้ในทีม Front-End และเอฟเฟกต์นั้นค่อนข้างดี
ปัจจุบันชุมชนมีเนื้อหาน้อยลงหรือง่ายเกินไปในพื้นที่นี้ (มีห้องแชทสาธารณะเพียงแห่งเดียว) นอกจากนี้ยังไม่สบายใจที่จะเป็น PM ในระหว่างกระบวนการพัฒนาธุรกิจดังนั้นฉันต้องการแยกตัวออกจากสิ่งที่เป็นเอกลักษณ์ทางธุรกิจและตระหนักถึงแอปพลิเคชัน IM ที่เรียบง่ายและสมบูรณ์ซึ่งไม่ได้ผสมผสานธุรกิจของ บริษัท เข้ากับฟังก์ชั่นง่าย ๆ รวมถึงเซิร์ฟเวอร์การจัดการและลูกค้า เป้าหมายของการเลียนแบบลูกค้าคือ WeChat เพราะฉันคุ้นเคยกับมันมากและไม่ต้องคิดมากเกี่ยวกับผลิตภัณฑ์มากเกินไป นอกจากนี้คนที่ลองใช้นั้นคุ้นเคยกับมันมากและไม่ต้องการค่าใช้จ่ายในการสื่อสารมากเกินไป
ในการพัฒนาชุดบริการส่งข้อความโต้ตอบแบบทันทีจำเป็นต้องมีชิ้นส่วนต่อไปนี้:
เกิดมาเพื่อกรอบและแอปพลิเคชันระดับองค์กร
เหตุผลที่ฉันเลือกเฟรมเวิร์กไข่ของอาลีบาบาตามการสนับสนุนคือพวกเขาทำงานได้ดีในการใช้งานขนาดใหญ่และความปลอดภัยภายใน เหตุผลที่พวกเขาไม่ได้เลือกรังก็คือมันเป็นเรื่องยากที่จะรวม socket.io เข้าด้วยกัน ORM ใช้ภาคต่อและฐานข้อมูลคือ MySQL ฉันเคยใช้มาก่อนดังนั้นจึงยากที่จะเริ่มต้น
โซลูชัน/การออกแบบส่วนหน้านอกกรอบ
เหตุผลในการเลือก Ant Design Pro คือฉันคุ้นเคยกับ Vue Family Bucket ฉันต้องการใช้โอกาสนี้เพื่อทำความคุ้นเคยกับกระบวนการพัฒนาของระบบนิเวศปฏิกิริยาทั้งหมดและรู้สึกถึงความแตกต่างที่สำคัญและเส้นทางที่แตกต่างกันของกรอบการพัฒนาที่สำคัญทั้งสองในประเทศจีน Ant Design Pro ได้รับการปล่อยตัวมาหลายปีแล้วและได้นำการปรับปรุงประสิทธิภาพมาสู่วิสาหกิจขนาดกลางและขนาดกลางซึ่งเหมาะสำหรับความต้องการของฉัน
เครื่องมือมาตรฐานที่พัฒนาโดย vue.js
ใช้ @vue/CLI เพื่อสร้างไคลเอนต์บริการ IM โครงการ H5 มือถือและเฟรมเวิร์ก UI ใช้ Youzan Vant ซึ่งรวมส่วนประกอบโอเพ่นซอร์สของฉัน Vue-Page-Stack และการควบคุมที่ดีกว่าของ Mr. Huang
ในฐานะวิศวกรส่วนหน้างานประจำวันส่วนใหญ่ไม่จำเป็นต้องคิดเกี่ยวกับความสัมพันธ์ของเอนทิตี อย่างไรก็ตามจากประสบการณ์จริงของฉันการทำความเข้าใจความสัมพันธ์ของเอนทิตีสามารถช่วยให้เราเข้าใจรูปแบบธุรกิจได้ดีขึ้น การปรับปรุงผลิตภัณฑ์และความเข้าใจทางธุรกิจเป็นสิ่งที่ดีสำหรับเรา เราสามารถค้นหาแง่มุมที่ไร้เหตุผลมากมายในระหว่างการตรวจสอบความต้องการ (ทำไมเราต้องบ่นเกี่ยวกับผู้จัดการผลิตภัณฑ์อีกครั้ง) หากเราสามารถเสนอได้ในเวลานี้เราจะใช้ความคิดริเริ่มเพื่อหลีกเลี่ยงการพัฒนาซ้ำในกระบวนการที่ตามมาและในเวลาเดียวกันเราสามารถสร้างปฏิสัมพันธ์ที่ค่อนข้างดีกับนักเรียนในด้านผลิตภัณฑ์ (แทนที่จะเผชิญหน้า) นี่คือความสัมพันธ์ของเอนทิตีที่สำคัญกว่า:
จากรูปด้านบนเราจะเห็นว่าผู้ใช้เป็นแกนหลักของแผนภาพความสัมพันธ์ทั้งหมด ต่อไปนี้คือความสัมพันธ์ระหว่างหน่วยงานต่าง ๆ :
ต่อไปนี้เป็นการแนะนำรายละเอียดเกี่ยวกับเซสชันบทบาทและการอนุญาต:
เมื่อเสร็จสิ้นแอปพลิเคชันการส่งข้อความแบบทันทีสิ่งแรกที่คุณต้องพิจารณาคือการสนทนาซึ่งเป็นหน้าต่างการสนทนาใน WeChat ของเรา ต้องใช้ความพยายามอย่างมากในการคิดเกี่ยวกับความสัมพันธ์ระหว่างการสนทนาและข้อความผู้ใช้และกลุ่มและในที่สุดก็สร้างความสัมพันธ์พื้นฐานดังต่อไปนี้:
กล่าวอีกนัยหนึ่งผู้ใช้ไม่มีความสัมพันธ์โดยตรงกับเซสชันและสามารถรับเซสชันผ่านการแชทเดี่ยวและแชทกลุ่มที่สอดคล้องกันของผู้ใช้เท่านั้น สิ่งนี้สามารถมีประโยชน์ต่อไปนี้:
เพื่อออกแบบระบบการจัดการการอนุญาตที่ยืดหยุ่นสากลและสะดวกสบายระบบนี้ใช้การควบคุม RBAC (การควบคุมการเข้าถึงตามบทบาท) เพื่อออกแบบแพลตฟอร์ม "การอนุญาตบทบาทผู้ใช้" ทั่วไปเพื่อความสะดวกในการขยายตัวในภายหลัง
RBAC (การควบคุมการเข้าถึงตามบทบาท) หมายถึงผู้ใช้ที่เกี่ยวข้องกับการอนุญาตผ่านบทบาท นั่นคือผู้ใช้มีหลายบทบาทและแต่ละบทบาทมีการอนุญาตหลายประการ (แน่นอนอย่ารวมบทบาทและสิทธิ์ที่ขัดแย้งกันเข้าด้วยกัน) ด้วยวิธีนี้รูปแบบการอนุมัติของ "ผู้ใช้บทบาทผู้ใช้" ถูกสร้างขึ้น ในโมเดลนี้โดยทั่วไปมีความสัมพันธ์หลายต่อหลายคนระหว่างผู้ใช้และบทบาทและระหว่างบทบาทและการอนุญาต
ระบบนี้มีบทบาทเริ่มต้นของผู้ดูแลระบบผู้ใช้ทั่วไปผู้ใช้ที่ถูกแบนและผู้ใช้ที่ถูกแบนและการอนุญาตที่แตกต่างกันถูกกำหนดให้กับบทบาทที่แตกต่างกัน ดังนั้นจึงจำเป็นต้องดำเนินการตรวจสอบความถูกต้องแบบรวม (ผ่านมิดเดิลแวร์) การประมวลผลสำหรับการกำหนดเส้นทางอินเตอร์เฟสเช่นการจัดการและการพูด วิธีการและวิธีการเฉพาะจะอธิบายอย่างละเอียดในโครงการ back-end ระบบนี้ใช้วิธีการของบทบาทและสิทธิ์ที่กำหนดไว้ล่วงหน้าชั่วคราว หากคุณต้องการขยายในอนาคตคุณสามารถแก้ไขบทบาทและการอนุญาต
ฉันไม่เคยเห็นด้านการจัดการของ WeChat แต่คุณสามารถจินตนาการได้ว่าผู้ดูแลระบบสามารถกำหนดค่าบทบาทของผู้ใช้และสิทธิ์และแก้ไขสถานะกลุ่ม:
หลังจากลงทะเบียนและเข้าสู่ระบบคุณสามารถเพิ่มเพื่อนและเข้าร่วมกลุ่มได้ตามปกติแก้ไขข้อมูลพื้นฐานส่วนบุคคลและแอปพลิเคชันกระบวนการ
ไม่สามารถเข้าสู่ระบบ
ตัวอย่างเช่นตอนนี้มีศูนย์ส่วนตัวเวอร์ชันใหม่ที่ต้องทดสอบออนไลน์ ขั้นแรกให้สร้างบทบาทใหม่ "ศูนย์ทดสอบส่วนบุคคล" จากนั้นกำหนดสิทธิ์ที่สอดคล้องกันให้กับบทบาท; จากนั้นกลุ่มผู้ใช้ทั่วไปและเลือกบางคนเพื่อกำหนดค่าบทบาทนี้เพื่อให้คุณสามารถทดสอบได้
มาพูดคุยเกี่ยวกับหลักการสื่อสารหลักของบริการส่งข้อความโต้ตอบแบบทันที เช่นเดียวกับบริการ HTTP ทั่วไปมีเซิร์ฟเวอร์และไคลเอนต์สำหรับการสื่อสาร แต่โปรโตคอลและวิธีการประมวลผลโดยละเอียดจะแตกต่างกัน
เนื่องจากเหตุผลทางประวัติศาสตร์โปรโตคอล HTTP กระแสหลักจึงเป็นโปรโตคอลไร้สัญชาติ (HTTP2 ไม่ได้ใช้กันอย่างแพร่หลายในช่วงเวลานั้น) โดยทั่วไปลูกค้าจะเริ่มคำขออย่างแข็งขันแล้วตอบกลับ ดังนั้นเพื่อให้ตระหนักว่าเซิร์ฟเวอร์จะส่งข้อมูลไปยังไคลเอนต์ส่วนหน้าจำเป็นต้องสำรวจความคิดเห็นของแบ็คเอนด์อย่างแข็งขัน วิธีนี้ไม่มีประสิทธิภาพและผิดพลาดได้ง่าย สิ่งนี้ทำในหน้าแรกของการจัดการของเราก่อน (5s หนึ่งครั้ง)
เพื่อให้บรรลุความต้องการนี้สำหรับฝั่งเซิร์ฟเวอร์เพื่อผลักดันข้อมูลอย่างแข็งขัน HTML5 เริ่มให้โปรโตคอลสำหรับการสื่อสารแบบเต็มเพล็กซ์ในการเชื่อมต่อ TCP เดียวคือ WebSocket WebSocket ทำให้การแลกเปลี่ยนข้อมูลระหว่างลูกค้าและเซิร์ฟเวอร์ง่ายขึ้นทำให้เซิร์ฟเวอร์สามารถส่งข้อมูลไปยังลูกค้าได้อย่างแข็งขัน โปรโตคอล WebSocket เกิดในปี 2551 และกลายเป็นมาตรฐานสากลในปี 2554 ปัจจุบันเบราว์เซอร์ส่วนใหญ่สนับสนุนแล้ว
การใช้ WebSocket นั้นค่อนข้างง่าย:
var ws = new WebSocket("wss://echo.websocket.org");
ws.onopen = function(evt) {
console.log("Connection open ...");
ws.send("Hello WebSockets!");
};
ws.onmessage = function(evt) {
console.log( "Received Message: " + evt.data);
ws.close();
};
ws.onclose = function(evt) {
console.log("Connection closed.");
};
ด้วยโปรโตคอล WebSocket เซิร์ฟเวอร์มีอาวุธขั้นสูงเพื่อผลักดันข้อมูลอย่างแข็งขัน ดังนั้นมีวิธีใดบ้างที่จะเข้ากันได้กับเบราว์เซอร์เก่าและใหม่? ในความเป็นจริงหลายคนคิดว่าสิ่งนี้และคำตอบคือ socket.io
socket.io socket.io ห่อหุ้มอินเทอร์เฟซ WebSocket เพิ่มเติมและสามารถเปลี่ยนไปใช้การสำรวจในเบราว์เซอร์เก่าเพื่อการสื่อสารโดยอัตโนมัติ (ผู้ใช้ของเราจะไม่รับรู้) โดยการสร้างชุดอินเทอร์เฟซแบบครบวงจรลดภาระการพัฒนาอย่างมาก ส่วนใหญ่มีข้อดีดังต่อไปนี้:
นี่คือโฮมเพจซ็อกเก็ต
เอ็นจิ้นการส่งข้อความโต้ตอบแบบทันทีที่เร็วและน่าเชื่อถือที่สุด (มีเอ็นจิ้นเวลาจริงที่เร็วและน่าเชื่อถือที่สุด)
ใช้งานง่ายจริงๆ:
var io = require('socket.io')(80);
var cfg = require('./config.json');
var tw = require('node-tweet-stream')(cfg);
tw.track('socket.io');
tw.track('javascript');
tw.on('tweet', function(tweet){
io.emit('tweet', tweet);
});
มามุ่งเน้นไปที่จุดสำคัญหลายประการในโครงการฝั่งเซิร์ฟเวอร์ เนื้อหาส่วนใหญ่จำเป็นต้องดูบนเว็บไซต์ทางการไข่
ใช้ Scaffolding npm init egg --type=simple ในการเริ่มต้นโครงการเซิร์ฟเวอร์ติดตั้ง MySQL (My Is Is Version 8.0) กำหนดค่ารหัสผ่านลิงก์ฐานข้อมูลที่จำเป็นสำหรับการสืบเนื่อง ฯลฯ และคุณสามารถเริ่มต้นได้
// 目录结构说明
├── package.json // 项目信息
├── app.js // 启动文件,其中有一些钩子函数
├── app
| ├── router.js // 路由
│ ├── controller
│ ├── service
│ ├── middleware // 中间件
│ ├── model // 实体模型
│ └── io // socket.io 相关
│ ├── controller
│ └── middleware // io独有的中间件
├── config // 配置文件
| ├── plugin.js // 插件配置文件
| └── config.default.js // 默认的配置文件
├── logs // server运行期间产生的log文件
└── public // 静态文件和上传文件目录
เราเตอร์ส่วนใหญ่จะใช้เพื่ออธิบายการติดต่อระหว่าง URL คำขอและคอนโทรลเลอร์ที่ดำเนินการโดยเฉพาะการดำเนินการในการดำเนินการนั่นคือ app/router
app/middleware/auth.jsapp/middleware/admin.js เนื่องจากระบบนี้มีบทบาทที่แตกต่างกันในฐานะผู้ดูแลระบบและผู้ใช้การสื่อสารทั่วไปจึงจำเป็นต้องมีการประมวลผลการรับรองความถูกต้องแบบครบวงจรสำหรับการกำหนดเส้นทางอินเทอร์เฟซของการจัดการและการสื่อสาร
ตัวอย่างเช่นเส้นทางด้านการจัดการ /v1/admin/... ฉันต้องการเพิ่มการรับรองความถูกต้องของผู้ดูแลระบบไปยังเส้นทางทั้งหมดในซีรี่ส์นี้ ในเวลานี้คุณสามารถใช้มิดเดิลแวร์เพื่อตรวจสอบสิทธิ์ ต่อไปนี้เป็นตัวอย่างเฉพาะของการใช้มิดเดิลแวร์ในเราเตอร์ผู้ดูแลระบบ
// middware
module.exports = () => {
return async function admin(ctx, next) {
let { session } = ctx;
// 判断admin权限
if (session.user && session.user.rights.some(right => right.keyName === 'admin')) {
await next();
} else {
ctx.redirect('/login');
}
};
};
// router
const admin = app.middleware.admin();
router.get('/api/v1/admin/rights', admin, controller.v1.admin.rightsIndex);
การรวมกันของภาคต่อ+MySQL ที่ใช้และไข่ยังมีการเรียงลำดับปลั๊กอินที่เกี่ยวข้อง Sequelize เป็น ORM ที่ใช้ในสภาพแวดล้อมโหนดรองรับ postgres, MySQL, Mariadb, SQLite และ Microsoft SQL Server ซึ่งค่อนข้างสะดวกในการใช้งาน คุณต้องกำหนดความสัมพันธ์โดยตรงระหว่างโมเดลและโมเดลก่อน หลังจากสร้างความสัมพันธ์แล้วคุณสามารถใช้วิธีการที่ตั้งไว้ล่วงหน้าได้
ข้อมูลพื้นฐานของโมเดลนั้นง่ายต่อการประมวลผล สิ่งที่ต้องให้ความสนใจคือการออกแบบความสัมพันธ์ระหว่างหน่วยงานนั่นคือผู้ร่วมงาน ต่อไปนี้เป็นคำอธิบายความสัมพันธ์ของผู้ใช้
// User.js
module.exports = app => {
const { STRING } = app.Sequelize;
const User = app.model.define('user', {
provider: {
type: STRING
},
username: {
type: STRING,
unique: 'username'
},
password: {
type: STRING
}
});
User.associate = function() {
// One-To-One associations
app.model.User.hasOne(app.model.UserInfo);
// One-To-Many associations
app.model.User.hasMany(app.model.Apply);
// Many-To-Many associations
app.model.User.belongsToMany(app.model.Group, { through: 'user_group' });
app.model.User.belongsToMany(app.model.Role, { through: 'user_role' });
};
return User;
};
ตัวอย่างเช่นความสัมพันธ์ระหว่างผู้ใช้และ userInfo เป็นความสัมพันธ์แบบหนึ่งต่อหนึ่ง หลังจากกำหนดแล้วเราสามารถใช้ user.setUserInfo(userInfo) เมื่อสร้างผู้ใช้ใหม่ เมื่อคุณต้องการรับข้อมูลพื้นฐานของผู้ใช้รายนี้คุณสามารถใช้ user.getUserInfo()
ความสัมพันธ์ระหว่างผู้ใช้และการสมัครเป็นแบบหนึ่งต่อหลายคนนั่นคือผู้ใช้สามารถสอดคล้องกับแอปพลิเคชันหลายรายการและปัจจุบันมีเพียงเพื่อนและแอปพลิเคชันกลุ่มเท่านั้นที่ใช้เท่านั้น:
เมื่อเพิ่มแอปพลิเคชันคุณสามารถใช้ user.addApply(apply) และเมื่อได้รับมันคุณสามารถใช้ได้ดังนี้:
const result = await ctx.model.Apply.findAndCountAll({
where: {
userId: ctx.session.user.id,
hasHandled: false
}
});
ความสัมพันธ์ระหว่างผู้ใช้และกลุ่มมีหลายต่อหลายคนนั่นคือผู้ใช้สามารถสอดคล้องกับหลายกลุ่มและกลุ่มสามารถสอดคล้องกับผู้ใช้หลายคน ด้วยวิธีนี้ Sequelize จะสร้างตารางกลาง user_group เพื่อให้บรรลุความสัมพันธ์นี้
ฉันมักจะใช้สิ่งนี้:
group.addUser(user); // 建立群组和用户的关系
user.getGroups(); // 获取用户的群组信息
ไข่ให้ปลั๊กอินไข่-ซ็อกเก็ต คุณต้องเปิดปลั๊กอินใน config/plugin.js หลังจากติดตั้ง Egg-Socket.io IO มีมิดเดิลแวร์และคอนโทรลเลอร์ของตัวเอง
เส้นทางของ IO นั้นแตกต่างจากคำขอ HTTP ทั่วไป โปรดทราบว่าเส้นทางที่นี่ไม่สามารถประมวลผลได้ด้วยมิดเดิลแวร์ (ฉันไม่ประสบความสำเร็จ) ดังนั้นฉันจึงจัดการการประมวลผลแบนในคอนโทรลเลอร์
// 加入群
io.of('/').route('/v1/im/join', app.io.controller.im.join);
// 发送消息
io.of('/').route('/v1/im/new-message', app.io.controller.im.newMessage);
// 查询消息
io.of('/').route('/v1/im/get-messages', app.io.controller.im.getMessages);
หมายเหตุ: ฉันคำนึงถึงความสัมพันธ์ทั้งกลุ่มและเพื่อนเป็นห้อง (นั่นคือเซสชั่น) เพื่อให้ฉันสามารถส่งข้อความไปยัง ROMM ได้โดยตรงและทุกคนภายในสามารถรับได้
มีมิดเดิลแวร์เริ่มต้นสองตัวหนึ่งคือมิดเดิลแวร์การเชื่อมต่อที่เรียกว่าเมื่อเชื่อมต่อและตัดการเชื่อมต่อซึ่งใช้เพื่อตรวจสอบสถานะการเข้าสู่ระบบและตรรกะทางธุรกิจของกระบวนการ อีกอย่างคือมิดเดิลแวร์แพ็คเก็ตที่เรียกว่าทุกครั้งที่ส่งข้อความซึ่งใช้ในการพิมพ์บันทึก
เนื่องจากการอนุญาตการโทรเป็นสิ่งที่ตั้งไว้ล่วงหน้าจึงถูกประมวลผลในคอนโทรลเลอร์
// 对用户发言的权限进行判断
if (!ctx.session.user.rights.some(right => right.keyName === 'speak')) {
return;
}
แชทแบ่งออกเป็นแชทเดียวและแชทเป็นกลุ่ม ข้อมูลการแชทรวมถึงข้อความทั่วไปรูปภาพวิดีโอและข้อความตำแหน่งซึ่งสามารถขยายออกเป็นคำสั่งซื้อหรือผลิตภัณฑ์ตามธุรกิจ
การออกแบบโครงสร้างของข้อความหมายถึงการออกแบบบริการของบุคคลที่สามหลายแห่งและยังได้รับการปรับแต่งร่วมกับสถานการณ์ของโครงการนี้เอง สามารถขยายได้ตามต้องการและมีคำอธิบายต่อไปนี้:
const Message = app.model.define('message', {
/**
* 消息类型:
* 0:单聊
* 1:群聊
*/
type: {
type: STRING
},
// 消息体
body: {
type: JSON
},
fromId: { type: INTEGER },
toId: { type: INTEGER }
});
ร่างกายเก็บเนื้อหาข้อความซึ่งใช้ในการจัดเก็บรูปแบบข้อความที่แตกต่างกันโดยใช้ JSON:
// 文本消息
{
"type": "txt",
"msg":"哈哈哈" //消息内容
}
// 图片消息
{
"type": "img",
"url": "http://nimtest.nos.netease.com/cbc500e8-e19c-4b0f-834b-c32d4dc1075e",
"ext":"jpg",
"w":360, //宽
"h":480, //高
"size": 388245
}
// 视频消息
{
"type": 'video',
"url": "http://nimtest.nos.netease.com/cbc500e8-e19c-4b0f-834b-c32d4dc1075e",
"ext":"mp4",
"w":360, //宽
"h":480, //高
"size": 388245
}
// 地理位置消息
{
"type": "loc",
"title":"中国 浙江省 杭州市 网商路 599号", //地理位置title
"lng":120.1908686708565, // 经度
"lat":30.18704515647036 // 纬度
}
ปัจจุบันมีเพียงหนึ่งเดียวเท่านั้นที่จะอัปเดตโทเค็นของ Baidu มันค่อนข้างง่ายที่นี่เพียงแค่อ้างถึงเอกสารอย่างเป็นทางการ
หน่วยการปรับแต่งบทสนทนาอัจฉริยะและแพลตฟอร์มบริการ
สิ่งนี้ค่อนข้างน่าสนใจ คุณสามารถสร้างหุ่นยนต์ใหม่และเพิ่มทักษะที่เกี่ยวข้องได้ที่ https://ai.baidu.com/ ฉันกำลังคุยกันที่นี่และมีคำถามและคำตอบที่ชาญฉลาด ฯลฯ
หากคุณไม่ต้องการเริ่มต้นคุณสามารถลบ ctx.service.baidu.getToken();
ก่อนอื่นคุณต้องกำหนดค่าในไฟล์การกำหนดค่า ฉันได้ จำกัด ขนาดไฟล์ที่นี่และรูปแบบไฟล์วิดีโอ iOS ข้ามไซต์:
config.multipart = {
mode: 'file',
fileSize: '3mb',
fileExtensions: ['.mov']
};
อินเทอร์เฟซแบบครบวงจรใช้เพื่อจัดการการอัปโหลดไฟล์ ปัญหาหลักคือการเขียนไฟล์และไฟล์เป็นรายการไฟล์ที่ส่งจากส่วนหน้า
for (const file of ctx.request.files) {
// 生成文件路径,注意upload文件路径需要存在
const filePath = `./public/upload/${
Date.now() + Math.floor(Math.random() * 100000).toString() + '.' + file.filename.split('.').pop()
}`;
const reader = fs.createReadStream(file.filepath); // 创建可读流
const upStream = fs.createWriteStream(filePath); // 创建可写流
reader.pipe(upStream); // 可读流通过管道写入可写流
data.push({
url: filePath.slice(1)
});
}
ฉันจัดเก็บ /public/upload/ ในไดเรกทอรีเซิร์ฟเวอร์ ไดเรกทอรีนี้ต้องการการกำหนดค่าไฟล์แบบคงที่:
config.static = {
prefix: '/public/',
dir: path.join(appInfo.baseDir, 'public')
};
เอกสารไข่อย่างเป็นทางการของบทนี้คือการฆ่าคุณไม่มีตัวอย่างคุณต้องอ่านซอร์สโค้ด มันแย่มาก ฉันได้ศึกษามานานก่อนที่ฉันจะรู้ว่าเกิดอะไรขึ้น
เนื่องจากฉันต้องการควบคุมรหัสผ่านบัญชีเข้าสู่ระบบได้อย่างอิสระมากขึ้นฉันไม่ใช้หนังสือเดินทางสำหรับการเข้าสู่ระบบรหัสผ่านบัญชี แต่ใช้การตรวจสอบความถูกต้องของอินเตอร์เฟสและเซสชัน
ต่อไปนี้เป็นคำอธิบายโดยละเอียดเกี่ยวกับกระบวนการบันทึกในการใช้แพลตฟอร์มบุคคลที่สาม (ฉันเลือก GitHub):
เปิดปลั๊กอิน:
// config/plugin.js
module.exports.passport = {
enable: true,
package: 'egg-passport',
};
module.exports.passportGithub = {
enable: true,
package: 'egg-passport-github',
};
// config.default.js
config.passportGithub = {
key: 'your_clientID',
secret: 'your_clientSecret',
callbackURL: 'http://localhost:3000/api/v1/passport/github/callback' // 注意这里非常的关键,这里需要和你在github上面设置的Authorization callback URL一致
};
this.app.passport.verify(verify);
const github = app.passport.authenticate('github', { successRedirect: '/' }); // successRedirect就是最后校验完毕后前端会跳转的路由,我这里直接跳转到主页了
router.get('/v1/passport/github', github);
router.get('/v1/passport/github/callback', github);
/v1/passport/github ที่ส่วนหน้าและเริ่มต้นการอนุญาต GitHub สำหรับแอปพลิเคชันนี้ หลังจากประสบความสำเร็จ GitHub จะไปที่ http://localhost:3000/v1/passport/github/callback?code=12313123123 ปลั๊กอิน GitHubPassport ของเราจะได้รับข้อมูลของผู้ใช้ใน GitHub หลังจากได้รับข้อมูลรายละเอียดแล้วเราจำเป็นต้องตรวจสอบข้อมูลผู้ใช้ใน app/passport/verify.js และเชื่อมโยงกับข้อมูลผู้ใช้ของแพลตฟอร์มของเราเองและกำหนดค่าให้กับเซสชัน // verify.js
module.exports = async (ctx, githubUser) => {
const { service } = ctx;
const { provider, name, photo, displayName } = githubUser;
ctx.logger.info('githubUser', { provider, name, photo, displayName });
let user = await ctx.model.User.findOne({
where: {
username: name
}
});
if (!user) {
user = await ctx.model.User.create({
provider,
username: name
});
const userInfo = await ctx.model.UserInfo.create({
nickname: displayName,
photo
});
const role = await ctx.model.Role.findOne({
where: {
keyName: 'user'
}
});
user.setUserInfo(userInfo);
user.addRole(role);
await user.save();
}
const { rights, roles } = await service.user.getUserAttribute(user.id);
// 权限判断
if (!rights.some(item => item.keyName === 'login')) {
ctx.body = {
statusCode: '1',
errorMessage: '不具备登录权限'
};
return;
}
ctx.session.user = {
id: user.id,
roles,
rights
};
return githubUser;
};
ให้ความสนใจกับรหัสข้างต้น หากเป็นการอนุญาตครั้งแรกผู้ใช้จะถูกสร้างขึ้น หากเป็นการอนุญาตที่สองผู้ใช้จะถูกสร้างขึ้น
เมื่อระบบถูกปรับใช้หรือเรียกใช้ข้อมูลและตารางบางอย่างจำเป็นต้องตั้งไว้ล่วงหน้าและรหัสอยู่ใน app.js และ app/service/startup.js
ตรรกะคือหลังจากเริ่มโครงการแล้วให้ใช้แบบจำลองเพื่อซิงโครไนซ์โครงสร้างตารางลงในฐานข้อมูลแล้วเริ่มสร้างข้อมูลพื้นฐานบางอย่าง:
หลังจากเสร็จสิ้นด้านบนข้อมูลเริ่มต้นเสร็จสมบูรณ์และสามารถทำงานได้ตามปกติ
ฉันซื้อเซิร์ฟเวอร์ centos บนคลาวด์ Tencent ชื่อโดเมนที่ฉันซื้อบน Alibaba Cloud ติดตั้งโหนด (12.18.2), Nginx และ MySQL8.0 และเริ่มต้นโดยตรงกับ CentOS front-end ใช้ nginx สำหรับพร็อกซีย้อนกลับ เนื่องจากทรัพยากรเซิร์ฟเวอร์ที่ จำกัด ไม่มีเครื่องมืออัตโนมัติเจนกินส์และนักเทียบท่าซึ่งนำไปสู่การดำเนินการด้วยตนเองบางอย่างเมื่ออัปเดต