目录

介绍

Headless CMS

什么是Headless CMS?

Headless CMS的优点

Headless CMS解决方案的局限性

使用HCMS的缺点

HCMS的局限性

何时何地使用Headless CMS?

RawCMS:构建自己的Headless CMS

为什么另一个Headless CMS?

RawCms特征选择

架构

服务层

认证

Lambda表达式

使用lambda添加自定义端点

验证数据

更改保存数据

插件

如何使用RawCMS

从Docker安装

从Zip Release安装

建立你自己的

兴趣点


  • 下载代码(来自GitHub
  • 见文档
  • Docker Hub拉出

介绍

在本文中,我们将了解Headless CMS,我们将了解它的优点以及何时使用方便。此外,我们将列举实际的主要限制。为了更好地理解HCMS如何在幕后工作,我将解释如何设计和构建RawCMS,一个带有Oauth2的Aspnet.Core Headless CMS,扩展插件系统,业务逻辑支持。该解决方案可在GitHub上获得,并作为演示版在docker hub上发布。

Headless CMS

什么是Headless CMS?

传统的CMS结合了内容和渲染部分,同时,Headless CMS仅关注内容。这似乎是一种限制,因为勉强说,你失去了一些东西。HCMS的目的是将逻辑与内容分离,从而实现简单的变更管理,并在许多组件中分解复杂的应用程序,每个组件都有其单一的责任。

朝着这个方向前进,HCMS可以取代实际上你正在调用的后端,并节省了许多创建CRUD语句的有用工作。

HCMS诞生于创建多组件应用程序,您可以快速更改表示逻辑和设计,这是一个很大的改进,当您在现代网站或应用程序上工作时,由于业务需求,您需要每年更换一次UI 。

许多供应商出售他们的产品并将其标记为“HCMS”仅仅是因为它是分离的(并且因为它听起来很酷并且可能推动销售改进)。在我看来,我与原始的整体定义有着严格的联系:Headless cms意味着API首先是非单片CMS,完全与接口或其他组件分离。

Headless CMS的优点

为什么要使用Headless CMS?我可以简单地说,在某些情况下,解耦系统,更容易更换前端并加快开发阶段是有用的,但我觉得有必要使用无序列表更好地解释。

  • 全渠道准备:在Headless CMS中创建的内容是“纯粹的”,您可以在您想要的每个上下文中使用。如果您在其上存储了一些新闻内容,您也可以在公共网站或内部网上发布,将数据输入到一个地方。
  • 低运营成本:Headless CMS是产品,所以,一旦你选择了一个好的产品,我预计它将是即插即用的。此外,与自定义解决方案相比,更新和错误修复来自供应商的免费提供。
  • 缩短产品上市时间:Headless CMS促进了敏捷的工作方式。您可以让多个团队参与后端和前端,这样可以减少时间。此外,由于HCMS区域是API消耗的数据存储的垂直解决方案,大部分事情已经完成,因此您必须专注于数据设计而不是技术细节(例如浪费时间考虑有效载荷,何时可以免费的使用Odata或Grahql)。
  • 垂直解决方案:HCMS做一件事。这使得学习和维护变得非常容易。
  • 灵活性:一旦你选择了你的HCMS(无论是本地还是云端),你的开发人员都可以使用他们喜欢的任何语言来实现前端。这意味着您可以自由地使用技术限制。

Headless CMS解决方案的局限性

与传统的CMS相比,HCMS相当年轻,因此,即使很多产品在过去几年诞生,大多数产品也不是那么成熟,无法完全取代传统的API后端。在这个阶段中,我将分享我对我发现的限制的经验。功能可能会因特定产品而异,如果是本地或saas解决方案。

实际上,主要有两种CMS Headless限制:

  • 使用HCMS的缺点
  • 您安装的产品的限制

使用HCMS的缺点

HCMS需要雇佣多个团队来实现工作并行化的好处。此外,由于HCMS没有任何渲染,所有的表示逻辑都被要求提供给客户端。这对于解耦很有用,但在所有情况下,您只有一个消费者解耦优势并不那么相关,并且您在数据获取过程中引入了更多的复杂性和延迟。另一个问题是关于业务逻辑。在哪里实施?如果你不想实现HCMS,你必须把它放到表示层,并且有多个消费者,当逻辑存在于多个地方时,您将复制它,陷入问题中。否则,尝试将其放入HMS,您会发现大多数云解决方案\产品都不那么灵活。这引入了下一个主题,所有HCMS的限制是什么?

HCMS的局限性

测试最重要的HCMS解决方案,我遇到了许多困难的情况,以下是最常见的限制列表。考虑到这取决于产品,有人可能有或没有,但一般来说,大多数都很常见。

  • 针对外部提供程序的身份验证:大多数解决方案不允许针对外部系统对用户进行身份验。我说的是最常见的情况,即您拥有一个中央身份验证系统,并且所有各方都会传递用户令牌\票证以代表用户进行操作。换句话说,如果我有一个oauth2服务器,我想在前端进行身份验证,并使用令牌向内部网的所有应用程序进行调用,而不仅仅是HCMS,并被识别为我自己。
  • 非标准输出格式:有些使用graphql或Odata,这很好,因为它为数据消耗提供了标准方法。问题是“某些”并不意味着“全部”,所以你必须注意选择你的HCMS。
  • 业务逻辑:在大多数情况下,不可能在运行时定义业务逻辑,在某些情况下也不可能扩展核心应用程序。
  • 可扩展性:很难找到一个解决方案,您可以编写自己的代码并更改业务逻辑或添加额外的东西。部分原因是许多供应商将其HCMS设计为哑数据存储,部分原因是管理可扩展性的复杂性。

何时何地使用Headless CMS?

Headless CMS是一个很好的机会,但在这里,我们必须了解使用它来优化成本/效益比的最佳方案。问题在于,使用常规HCMS,定制非常有限,因此如果您不在正确的情况下,很难将HCMS混合以实现业务需求。而且,像裸数据存储一样使用它会使它变得毫无意义。

何时使用HCMS很方便:

  • 在一段时间里,UI上有很多变化
  • 许多共享相同信息的应用程序和一个管理它的团队
  • 您对数据的业务逻辑很少
  • 你可以聘请多个团队(be + fe)

您何时不应该使用HCMS:

  • 有一个符合您需求的垂直解决方案(例如,您希望博客使用wordpress)
  • 你有很多业务逻辑
  • 你不是数据的主人

RawCMS:构建自己的Headless CMS

在本章中,我们将看到RawCMS是什么以及我如何使用ASP.NET Core,mongodb,Docker和一些幻想创建Headless CMS。

为什么另一个Headless CMS?

RawCMS的目的是在没有HCMS的共同限制的情况下生成HCMS(......以及在新技术上训练有趣的东西;-))

RawCms特征选择

所以我们将提出的功能:

  • 可以使用oauth2自省(或内置的auth系统)对其他auth系统进行身份验证的可能性
  • 可以使用挂钩/事件系统添加业务逻辑的可能性
  • 可以添加自定义端点来管理与数据无关的事件的可能性
  • 可以在插件系统中添加功能的可能性
  • 验证数据的可能性
  • 使用多种协议公开数据,如webapi,GraphQL,Odata

架构

基本上,我将实现的架构如下。实际上,插件部分有一些限制,缺少工作流管理,但其他部分功能齐全。

服务层

服务层是系统的核心部分。使用mongodb实体上的常规JObject映射,您可以在mongo集合中存储您想要的任何内容,所有数据都是无类型的。

这是本类中最相关的部分,用于解释它的工作原理。

public class CRUDService
{public JObject Get(string collection, string id){//Create filter by id (all entity MUST have an id field, called _id by convention)FilterDefinition<BsonDocument> filter = Builders<BsonDocument>.Filter.Eq("_id", BsonObjectId.Create(id));IFindFluent<BsonDocument, BsonDocument> results = _mongoService.GetCollection<BsonDocument>(collection).Find<BsonDocument>(filter);return ConvertBsonToJson(json);}public ItemList Query(string collection, DataQuery query){FilterDefinition<BsonDocument> filter = FilterDefinition<BsonDocument>.Empty;if (query.RawQuery != null){filter = new JsonFilterDefinition<BsonDocument>(query.RawQuery);}InvokeAlterQuery(collection, filter);IFindFluent<BsonDocument, BsonDocument> results = _mongoService.GetCollection<BsonDocument>(collection).Find<BsonDocument>(filter).Skip((query.PageNumber - 1) * query.PageSize).Limit(query.PageSize);long count = Count(collection, filter);        return new ConverToItemList(results, (int)count, query.PageNumber, query.PageSize);}public JObject Update(string collection, JObject item, bool replace){//Invoke validation eventsInvokeValidation(item, collection);// create collection if not existsEnsureCollection(collection);FilterDefinition<BsonDocument> filter = Builders<BsonDocument>.Filter.Eq("_id", BsonObjectId.Create(item["_id"].Value<string>()));//Invoke presave eventsInvokeProcess(collection, ref item, SavePipelineStage.PreSave);//insert id (mandatory)BsonDocument doc = BsonDocument.Parse(item.ToString());doc["_id"] = BsonObjectId.Create(item["_id"].Value<string>());//set into "incremental" update modedoc = new BsonDocument("$set", doc);        UpdateOptions o = new UpdateOptions(){IsUpsert = true,BypassDocumentValidation = true};if (replace){_mongoService.GetCollection<BsonDocument>(collection).ReplaceOne(filter, doc, o);}else{BsonDocument dbset = new BsonDocument("$set", doc);_mongoService.GetCollection<BsonDocument>(collection).UpdateOne(filter, dbset, o);}//Post save eventsInvokeProcess(collection, ref item, SavePipelineStage.PostSave);return JObject.Parse(item.ToJson(js));}
}

认证

认证部分完成添加身份服务器并使用基于RawCms设置的不同配置。通过这种方式,我们可以使用内部身份服务器(其他人获取我们的令牌,我们拥有用户数据)或与其他认证系统集成(我们在请求标头中获取令牌,我们够能将其推送到其他oauth系统上)。

这是代码中最相关的部分。此代码在身份验证插件启动期间调用,并从数据库获取配置。与该类的认证配置无关的所有代码部分都被省略。

public override void ConfigureServices(IServiceCollection services)
{base.ConfigureServices(services);//configuration came from constructorservices.Configure<ConfigurationOptions>(configuration);services.AddSingleton<IUserStore<IdentityUser>>(x => { return userStore; });//... registering all identity server services for user and roles (all code omitted)services.AddSingleton<IUserClaimsPrincipalFactory<IdentityUser>, RawClaimsFactory>();// configure identity server with in-memory stores, keys, clients and scopesservices.AddIdentityServer().AddDeveloperSigningCredential().AddInMemoryPersistedGrants().AddInMemoryIdentityResources(config.GetIdentityResources()).AddInMemoryApiResources(config.GetApiResources()).AddInMemoryClients(config.GetClients()).AddAspNetIdentity<IdentityUser>().AddProfileServiceCustom(userStore);if (config.Mode == OAuthMode.External){OAuth2IntrospectionOptions options = new OAuth2IntrospectionOptions{//... set option basing on config (code omitted)            };options.Validate();services.AddAuthentication(OAuth2IntrospectionDefaults.AuthenticationScheme).AddOAuth2Introspection(x =>{x = options;});}else{services.AddAuthentication(OAuth2IntrospectionDefaults.AuthenticationScheme).AddIdentityServerAuthentication("Bearer", options =>{//... set option basing on config (code omitted)});}services.AddMvc(options =>{//this apply custom authentication like apitoken other than oauth standardoptions.Filters.Add(new RawAuthorizationAttribute(config.ApiKey, config.AdminApiKey));});
}

Lambda表达式

Lamba是一个简单的命令模式实现,该名称的灵感来自无服务器模型,您可以将函数公开为rest端点。基于此,您可以通过实现lamba来调整系统中的所有内容。每个lambda实例都在运行时发现,并根据lamba类型和事件调用,并将数据上下文传递给它。

下面给出一些lambda示例。

使用lambda添加自定义端点

public class DummyRest : RestLambda
{public override string Name => "DummyRest";public override string Description => "I'm a dumb dummy request";public override JObject Rest(JObject input){JObject result = new JObject(){{ "input",input},{ "now",DateTime.Now},};return result;}
}

验证数据

public class MyCustomValidation : SchemaValidationLambda
{public override string Name => "My custom Validation";public override string Description => "Provide  entity validation";public override List<Error> Validate(JObject input, string collection){//do here all check with datareturn ImplementCheckHere(input, collection);}
}

更改保存数据

public class AuditLambda : PreSaveLambda
{public override string Name => "AuditLambda";public override string Description => "Add audit settings";public override void Execute(string collection, ref JObject Item){if (!Item.ContainsKey("_id") || string.IsNullOrEmpty(Item["_id"].ToString())){Item["_createdon"] = DateTime.Now;}Item["_modifiedon"] = DateTime.Now;}
}

插件

插件系统背后的想法是创建一个项目,开发您的功能,将DLL扔进bin文件夹并使其可用于应用程序。其中的主要部分将被讨论成一篇专门的文章,因为解释和偏离主题需要很长时间。我只想在这里展示一下插件系统的原理。这也意味着您可以使用nuget作为交付系统或功能市场。

public class GraphQLPlugin : RawCMS.Library.Core.Extension.Plugin
{public override string Name => "GraphQL";public override string Description => "Add GraphQL CMS capabilities";public override void Init(){Logger.LogInformation("GraphQL plugin loaded");}public override void ConfigureServices(IServiceCollection services){//will be triggered on Startup.cs ConfigureServicesbase.ConfigureServices(services);}private void SetConfiguration(Plugin plugin, CRUDService crudService){//used to receive configuration from system}public override void Configure(IApplicationBuilder app, AppEngine appEngine){// will be triggered on Startup.cs Configurebase.Configure(app, appEngine);}
}

如何使用RawCMS

为了让用户测试这个解决方案,我实现了很多选项。

从Docker安装

这是最方便的。您可以在文档内找到一个docker compose示例,或者您可以使用docker run然后链接到mongodb实例。

docker run rawcms -p 80:8081

或使用docker compose:

version: '3'
services:rawcms:build: .ports:- "54321:54321"   links:- mongoenvironment:- MongoSettings__ConnectionString=mongodb://mongo:27017/rawCms- PORT=54321- ASPNETCORE_ENVIRONMENT=Dockermongo:image: mongo

环境变量MongoSettings__ConnectionString用于将连接字符串传递给应用程序。

从Zip Release安装

如果您尚未准备好容器,可以从GitHub版本下载zip文件,并将其作为常规ASP.NET Core应用程序手动部署。

建立你自己的

第三种可能性是分解解决方案,并在本地发挥作用。目前,您的设置中没有任何nuget包,因此建议的最佳解决方案是将github repo添加为子模块或子树。

兴趣点

HMCS是解耦架构和避免无用工作的绝佳机会。这可能会带来诸如减少时间和成本等好处,使各方独立。当然,这不是灵丹妙药,您必须了解垂直解决方案是否更方便,或者您的企业登录是否避免你使用它。

我试图实现HCMS,我们看到了一个非常重要的话题。这很有趣,我们了解如何实现最重要的主题,以超越HCMS的实际技术限制。

原文地址:https://www.codeproject.com/Articles/1278159/Inside-Headless-CMS

Headless CMS 的内部相关推荐

  1. 什么是 Headless CMS?

    什么是 Headless CMS? Headless 内容管理是当今 Web 设计的关键开发,它将前端客户端应用程序与后端内容管理系统分离开. 因此,Headless CMS 负责(后端)内容管理服务 ...

  2. Headless CMS - 打破“设计优先”的怪圈

    什么是 Headless CMS? 为什么 Headless CMS 带有真正的革命性?因为它严格的将内容和格式分离,使我们回归到内容管理的本源.这种变化必然会带来一些不确定性.因此,在开始您的第一个 ...

  3. java html5 cms,企业内部cms业务管理系统html5简洁的模板

    模板描述:企业内部 cms业务管理系统 html5 简洁的 模板.企业内部cms业务管理系统html5简洁的模板,bootstrap框架,pc和wap通用 代码结构 1. 引入CSS 2. 引入JS ...

  4. Headless CMS Sanity 数据建模——定义文档内容的结构

    定义内容的结构. 使用代码定义内容模型是设计使然.它使版本控制变得更容易,并使开发人员能够控制数据结构的布局方式.我们让在界面中添加.更改和删除字段变得毫不费力. 观看Schema 工作原理的视频,或 ...

  5. restful解决什么问题_当您陷入RESTful,WordPress和一个困难的地方时,如何解决CMS问题...

    restful解决什么问题 by Jessica Duffin Wolfe 杰西卡·达芬·沃尔夫(Jessica Duffin Wolfe) 当您陷入RESTful,WordPress和一个困难的地方 ...

  6. sanity测试_Sanity.io入门-您可以自定义的无头CMS

    sanity测试 If you're looking for a headless CMS with amazing features and tons of customization, look ...

  7. 2020年那种语言最受欢迎_2020年15种最佳和最受欢迎的CMS平台(比较)

    2020年那种语言最受欢迎 Are you wondering what CMS platform to use for building your website? 您是否想知道使用什么CMS平台来 ...

  8. 一篇文章教你弄懂java CMS垃圾回收日志

    文章目录 一.CMS垃圾回收器介绍 二.CMS JVM运行参数 三.CMS收集器运行过程 1.初始标记(CMS initial mark) 2.并发标记(CMS concurrent mark) 3. ...

  9. 30.jvm.gc(GC之详解CMS收集过程和日志分析)

    30.jvm.gc(GC之详解CMS收集过程和日志分析) 30.1.话题引入 30.2.ParNew and CMS 30.3.日志 30.3.1.GC日志初体验 30.3.2.Minor GC 30 ...

最新文章

  1. 深度学习(二十六)Network In Network学习笔记-ICLR 2014
  2. 蓝桥杯 第三届C/C++预赛真题(7) 放棋子(水题)
  3. [译]关于NODE_ENV,哪些你应该了解
  4. 怎么让员工服从管理_为什么现在的员工执行力和服从性越来越差,管理一严格就辞职?...
  5. php中get_featured_posts()是什么意思,WordPress的Get_Posts()函数详解
  6. python复习-正则表达式
  7. 微信小程序-上传多张图片加进度条(支持预览、删除)
  8. max_workers解释
  9. vue-tv-focusable
  10. 使用jxls导出报错:Connot load XLS transformer please make sure a Transformer implementation is in classpath
  11. macbook视频格式转换_如何将Mac视频格式转换
  12. SUMO地图中添加交通流
  13. 删除安卓7.1源码中自带的Japanese IME输入法
  14. 智能证件录入系统——电子护照阅读器
  15. 笔记本手机都能用的充电器,做的只有乒乓球大小,AOHi 65W氮化镓充电器体验
  16. Java类的加载及父类子类加载顺序
  17. java.lang.NullPointerException: pattern
  18. C4Dr18安装完成双击图标无任何反应,缺失libmmd.dll
  19. CSS进阶篇——展示 (display)
  20. 项目计划管理软件:GanttProject

热门文章

  1. java字符串拼接_这样写Java,同事直呼666
  2. html5+上下左右边界顺序,详解canvas绘制多张图的排列顺序问题
  3. android 原生开发 3d地图 下载_arcgis api 3.x for js 入门开发系列二不同地图服务展示(附源码下载)...
  4. 计算机系毕业生自我评价,计算机系应届毕业生自我评价范文
  5. probe request帧结构_WIFI基础知识(802.11)
  6. spark的python开发安装方式_windows下安装spark-python
  7. vue svg sprite loader_Vue项最佳实践
  8. java中注释的嵌套,java – 使用mybatis注释获取嵌套对象
  9. 三菱的触摸屏usb驱动_如何实现一个TK6071IP的触摸屏驱动两个三菱FX1S-30MT的PLC?...
  10. python之数字操作