【大型网站技术实践】初级篇:海量图片的分布式存储设计与实现

news/2024/5/9 17:04:15/文章来源:https://blog.csdn.net/weixin_33747129/article/details/86054001

说明:本文是我阅读计算机工程期刊《海量图片的分布式存储及负载均衡研究》一文的学习笔记和具体实践,原文地址在本文底部。

一、研究背景:性能与资金,二者可兼得乎?

1.1 那么问题来了?

  随着互联网的发展,许多大中型的网站都保存了大量的图片资源,用户在访问这些图片资源异常丰富的网站(如淘宝、京东等电子商务网站)时,网页中的图片信息占据了页面数据流量的很大部分,那么问题也来了:

  (1)由于受客户端浏览器限制,无法从一台服务器上同时下载页面中所有图片信息;

PS:当一个网页被浏览时,Web服务器与浏览器建立连接,每个连接表示一个并发。当页面包含多个图片时,Web服务器与浏览器会产生多个连接,同时发送文字和图片以提高浏览速度。因此,页面中图片越多Web服务器受到的压力也就越大。同时由于受到浏览器本身的并发连接数限制(2个~6个并发),意味着页面上有多于并发连接数限制的图片时,也不能并行地把所有图片同时下载和显示。

  (2)由于图片保存在物理服务器上,访问图片需要频繁进行I/O操作:因此当并发用户数越来越多时,I/O操作就会成为整个系统的性能瓶颈

  (3)由于受操作系统的限制,一个目录中能存放的图片文件数量也是有限的:随着图片资源不断增加,如何有效管理和维护图片也是一个难题;

1.2 山东济南找蓝翔?

  (1)对于少数大型网站系统,由于自身具有雄厚的资金和人力资源,可采用NFS、CDN、Lighttpd、反向代理、负载均衡等技术提高用户访问速度;但是,这些技术需要庞大的资金来支持。

  (2)对于多数中小型网站系统,有木有一种方案适用于中等规模商务网站的海量图片数据分布式动态存储及负载均衡的解决方案?该方案可否只需增加很少的硬件成本,即可提升网站的访问速度,并且可以根据需要动态调整图片服务器的数量及图片的存储目录,确保系统具有可扩展性和伸缩性。

SUMMARY:需求永远是那么美好,使用最少的money干尽量多的事情!正在我们决定放弃开发岗位去蓝翔学挖掘机技术的时候,我们突然发现有那么多的技术先驱已经给我们指明了道路。

二、架构设计:构建图片服务器集群

  对于小型网站,由于数据规模小,可以把网站所有页面和图片统一存放在一个主目录下,这样的网站对系统架构、性能要求都很简单。但大中型网站都保存有海量级的图片文件,所采用的技术更是涉及广泛,从硬件到软件、编程语言、数据库、Web服务器、防火墙等各个领域都有较高要求。因此,有必要设立单独的图片服务器来专门存放图片,把图片数据的流量从Web服务器上分离开,这样的架构可以有效缓解Web服务器的I/O性能瓶颈,提升用户的访问速度。

2.1 系统设计目标  

  基于以上的考虑,我们希望的设计目标是:

  (1)图片能进行分布式存储; 

  (2)图片服务器能实现负载均衡;  

  (3)能根据用户访问量及网站图片数据量的增加能动态添加图片服务器节点

  (4)图片服务器节点的动态调整对网站用户而言是透明的,并且不会中断系统的正常运行

  其中,(1)和(2)是针对系统的高可用和伸缩性,而(3)和(4)则是针对系统的高可用和可扩展而言的。

2.2 系统架构设计

  系统整体架构如上图所示:包括客户端、Web服务器、数据库服务器、图片服务器集群4个部分。

  (1)Web服务器部署网站的Web页面,用于响应客户端用户的请求。当用户浏览网页时,Web服务器响应请求并访问数据库服务器,获得网页中所有图片的URL路径,然后生成页面并返回给客户端;

  (2)客户端接收该页面并根据页面中的图片URL路径自动从不同的图片服务器下载并显示相应图片。

  (3)数据库服务器用于记录所有图片的编号以及图片的存放位置等信息,同时需要记录所有图片服务器的配置及当前状态信息。

  (4)图片服务器集群用于存放网站的所有图片信息,该集群的服务器数量可以根据需要动态增加或删减。

三、系统实现:一种简单且价廉可用的方案

3.1 数据库设计与实现:两张简单的表

  Web服务器需要及时掌握所有图片服务器的状态和信息才能动态决定把图片保存到哪一台图片服务器。因此,需要把所有的图片服务器的状态信息全部纪录到数据库服务器中,记录图片服务器信息和状态的表格式如下图所示:可以清楚地看出,图片服务器信息表中记录了图片服务器的ID、名称、URL、最大存储数量、当前已存数量以及服务器的状态(True:可用,False:不可用),每个图片服务器下会有多个图片信息记录,因此它们是一对多的关系。

  (1)图片服务器状态信息表建表语句:

CREATE TABLE [dbo].[ImageServerInfo]([ServerId] [int] IDENTITY(1,1) NOT NULL,[ServerName] [nvarchar](32) NOT NULL,[ServerUrl] [nvarchar](100) NOT NULL,[PicRootPath] [nvarchar](100) NOT NULL,[MaxPicAmount] [int] NOT NULL,[CurPicAmount] [int] NOT NULL,[FlgUsable] [bit] NOT NULL,CONSTRAINT [PK_ImageServerInfo] PRIMARY KEY CLUSTERED 
([ServerId] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]
View Code

  (2)图片记录信息表建表语句:

CREATE TABLE [dbo].[ImageInfo]([Id] [int] IDENTITY(1,1) NOT NULL,[ImageName] [nvarchar](100) NOT NULL,[ImageServerId] [int] NOT NULL,CONSTRAINT [PK_ImageInfo] PRIMARY KEY CLUSTERED 
([Id] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]GOALTER TABLE [dbo].[ImageInfo]  WITH CHECK ADD  CONSTRAINT [FK_ImageInfo_ImageServerInfo] FOREIGN KEY([ImageServerId])
REFERENCES [dbo].[ImageServerInfo] ([ServerId])
GOALTER TABLE [dbo].[ImageInfo] CHECK CONSTRAINT [FK_ImageInfo_ImageServerInfo]
GO
View Code

3.2 文件上传与浏览系统实现:一个ASP.Net MVC应用程序

  这里我们使用一个ASP.NET MVC应用程序部署在Web服务器上,这个应用程序作为Web网站向客户提供上传和浏览的服务。因此,它最重要的功能就是:

  一、接收用户上传的文件,并转交给图片服务器的相关处理程序进行处理和保存;

  二、取得所有图片服务器中保存的有效图片路径,返回给客户端浏览器,再由客户端浏览器对图片路径向图片服务器集群进行请求;

  3.2.1 设计Controller

    public class HomeController : Controller{IImageServerInfoRepsitory _imageServerInfoRepository;public HomeController(){// 这里可以借助IoC实现依赖注入this._imageServerInfoRepository = new ImageServerInfoRepository();}#region 01.Action:上传页面//// GET: /Home/public ActionResult Index(){return View();}#endregion#region 02.Action:上传图片public ActionResult Upload(){HttpPostedFileBase file = Request.Files["fileUpload"];if (file.ContentLength == 0){return Content("<script type=\"text/javascript\">alert(\"您还未选择要上传的图片!\");location.href=\"/Home/Index\";</script>");}// 获取上传的图片名称和扩展名称string fileFullName = Path.GetFileName(file.FileName);string fileExtName = Path.GetExtension(fileFullName);if (!CommonHelper.CheckImageFormat(fileExtName)){return Content("<script type=\"text/javascript\">alert(\"上传图片格式错误,请重新选择!\");location.href=\"/Home/Index\";</script>");}// 获取可用的图片服务器集合List<ImageServerInfo> serverList = this._imageServerInfoRepository.GetAllUseableServers();if(serverList.Count == 0){return Content("<script type=\"text/javascript\">alert(\"暂时没有可用的图片服务器,请稍后再上传!\");location.href=\"/Home/Index\";</script>");}// 获取要保存的图片服务器索引号int serverIndex = CommonHelper.GetServerIndex(serverList.Count);// 获取指定图片服务器的信息string serverUrl = serverList[serverIndex].ServerUrl;int serverID = serverList[serverIndex].ServerId;string serverFullUrl = string.Format("http://{0}/FileUploadHandler.ashx?serverId={1}&ext={2}",serverUrl, serverID, fileExtName);// 借助WebClient上传图片到指定服务器WebClient client = new WebClient();client.UploadData(serverFullUrl, CommonHelper.StearmToBytes(file.InputStream));return Content("<script type=\"text/javascript\">alert(\"上传图片操作成功!\");location.href=\"/Home/Index\";</script>");} #endregion#region 03.Action:显示图片public ActionResult Show(){var imageServerList = this._imageServerInfoRepository.GetAllUseableServers();ViewData["ImageServers"] = imageServerList;return View();}#endregion}
View Code

  (1)图片上传的过程比较复杂,首先Web服务器接收客户端的访问请求并访问数据库,在Web端需要取得所有可用的图片服务器的集合,这里使用到了一个GetAllUseableServers方法,它的实现如下:可以看出,我们需要判断FlgUsable标志为true以及CurPicAmount当前存储量小于MaxPicAmount最大存储量这两个条件。如果有宕机或不可用的情况,需要管理员将那一行的FlgUsable设置为false。

        public List<ImageServerInfo> GetAllUseableServers(){List<ImageServerInfo> serverList = db.ImageServerInfo.Where<ImageServerInfo>(s => s.FlgUsable == true&& s.CurPicAmount < s.MaxPicAmount).ToList();return serverList;}

  (2)这里用到了一个GetServerIndex的方法,它的实现如下:从图片服务器状态信息表筛选出可用的图片服务器集合记作C,并获取集合的总记录数N。然后用随机函数产生一个随机数R1,用R1与N进行取余运算记作I=R1%N。则C[I]即为要保存图片的图片服务器。这个方法基本保证了我们的图片服务器的负载是一个比较均衡的比例。(当然,我们可以设计一个更加高效的,类似于一致性哈希算法的哈希函数)

        #region 01.获取服务器索引号/// <summary>/// 01.获取服务器索引号/// </summary>/// <param name="serverCount">服务器数量</param>/// <returns>索引号</returns>public static int GetServerIndex(int serverCount){Random rand = new Random();int randomNumber = rand.Next();int serverIndex = randomNumber % serverCount;return serverIndex;} #endregion

  (3)最后,Web端程序借助了WebClient将服务器ID、文件扩展名以及图片的字节流转交给了具体的图片服务器处理程序:Web端程序的工作就到此结束,但是这里木有采用异步,因此需要等待图片服务器的工作结束。

  WebClient client = new WebClient();client.UploadData(serverFullUrl, CommonHelper.StearmToBytes(file.InputStream));

PS:由于B/S架构本身技术限制,图片无法通过Web服务器直接上传到不同的图片服务器中。因此,这里需要借助类似于WebClient、HttpWebRequest等类向具体的图片服务器发送Http请求,或者是通过在图片服务器上部署Web Service,以便Web服务器通过调用该服务执行图片的保存操作。

  3.2.2 设计View

  (1)上传页面:

@{Layout = null;
}<!DOCTYPE html><html>
<head><meta name="viewport" content="width=device-width" /><title>Index</title><link href="~/Resources/css/mystyle.css" rel="stylesheet" /><script src="~/Resources/js/jquery-1.8.0.min.js"></script><script type="text/javascript">$(function () {$("#btnUpload").click(function () {$("#loading").show();});});</script>
</head>
<body><div id="mainarea"><fieldset><legend id="title">图片上传系统</legend><form method="post" action="/Home/Upload" enctype="multipart/form-data"><table><tr><td><input id="fileSelect" type="file" name="fileUpload" /></td><td><input id="btnUpload" type="submit" value="上传图片" /></td></tr><tr><td id="tiparea" colspan="2"><div id="loading"><img class="imgstyle" src="~/Resources/image/ico_loading2.gif" />正在上传中,请稍候...</div></td></tr></table></form></fieldset><p id="footer">Copyright &copy; 2014 Edison Chou</p></div>
</body>
</html>
View Code

  在form标签中不要忘了:enctype="multipart/form-data"

  (2)浏览页面:

@{Layout = null;
}
@using MyImageDFS.Model;
<!DOCTYPE html><html>
<head><meta name="viewport" content="width=device-width" /><title>Show</title><link href="~/Resources/css/mystyle.css" rel="stylesheet" /><script src="~/Resources/js/jquery-1.8.0.min.js"></script>
</head>
<body><div id="mainarea"><fieldset><legend id="title">图片浏览系统</legend><table id="imageTable" cellspacing="1" cellpadding="1">@foreach (ImageServerInfo server in (List<ImageServerInfo>)ViewData["ImageServers"]){foreach (ImageInfo image in server.ImageInfo){<tr><td><img class="showimage" alt="@image.ImageName" src="@string.Format("http://{0}{1}",server.ServerUrl, image.ImageName)" /></td></tr>}}</table></fieldset></div>
</body>
</html>
View Code

  这里主要通过对不同的图片服务器发送请求获取图片,从而降低Web服务器的I/O性能瓶颈,加快整个系统的响应时间。

3.3 图片服务器文件接收系统实现:一个ASP.Net一般处理程序

        /// <summary>/// 接收Web服务器传递过来的文件信息并保存到指定目录文件下,最后将文件信息存入数据库中/// </summary>/// <param name="context"></param>public void ProcessRequest(HttpContext context){context.Response.ContentType = "text/plain";// 接收文件的扩展名string fileExt = context.Request["ext"];if (string.IsNullOrEmpty(fileExt) || string.IsNullOrEmpty(context.Request["serverId"])){return;}// 图片所在的服务器的编号int serverID = Convert.ToInt32(context.Request["serverId"]);// 图片要存放的物理路径string imageDir = "/Upload/" + DateTime.Now.Year + "/" + DateTime.Now.Month + "/" + DateTime.Now.Day + "/";string serverPath = Path.GetDirectoryName(context.Request.MapPath(imageDir));if(!Directory.Exists(serverPath)){// 如果目录不存在则新建目录
                Directory.CreateDirectory(serverPath);}// 取得GUID值作为图片名string newFileName = Guid.NewGuid().ToString();// 取得完整的存储路径string fullSaveDir = imageDir + newFileName + fileExt;using (FileStream fileStream = File.OpenWrite(context.Request.MapPath(fullSaveDir))){// 将文件数据写到磁盘上
                context.Request.InputStream.CopyTo(fileStream);// 将文件信息存入数据库ImageInfo imageInfo = new ImageInfo();imageInfo.ImageName = fullSaveDir; // 存储图片真实路径imageInfo.ImageServerId = serverID; // 存储服务器编号this._imageFacadeRepository.Add(imageInfo);}}
View Code

  (1)这是一个简单的一般处理程序,它首先接收要保存的图片扩展名以及服务器ID,根据规则生成具体的保存路径,然后通过I/O流将图片保存到该服务器的磁盘上;

  (2)最后将更改数据库信息记录,由于要同时对两张表进行修改,这里我们需要对这个方法进行一个简单的封装,使之成为一个事务。现在我们来看看这个Add方法的实现:

        public ImageStatusEnum Add(ImageInfo imageEntity){// 首先是图片信息表
            db.ImageInfo.Add(imageEntity);// 其次是图片服务器信息表ImageServerInfo serverEntity = db.ImageServerInfo.FirstOrDefault(s => s.ServerId == imageEntity.ImageServerId);if (serverEntity != null){// 当前服务器存储数量+1serverEntity.CurPicAmount += 1;}// 一起提交到SQL Server数据库中int result = db.SaveChanges();if (result > 0){return ImageStatusEnum.Successful;}else{return ImageStatusEnum.Failure;}}

3.4 简单测试图片文件的上传与浏览

  (1)测试前的准备工作

  ①由于我的电脑不支持64位的虚拟机,因此原本打算在VMware中部署三台Windows Server 2008 R2作为Web服务器和图片服务器的打算被撤销(没法任性地做实践,我很不开心啊)。于是,我采用了在一台电脑上部署多个应用,用端口号区分不同的服务程序来模拟效果。

  ②将Web应用程序和图片服务应用程序分别编译发布,并部署到IIS中,分配不同的端口号:图片上传与浏览程序8000端口,图片服务器的文件处理程序分别占用8010与8020端口;

  (2)测试图片文件上传与存储

  由于连续截屏所生成的gif图片太大,因此这里只选择了截取其中一次上传的过程作为展示。在我连续上传操作了N次之后,现在我们来看看两个文件服务器所在的文件夹中是否有我们上传的图片文件(这里主要是看部署的程序所在的文件目录,其中有一个专门保存图片的文件目录Upload)

  ①图片服务器A所保存的文件:

  ②图片服务器B所保存的文件:

  总结:从图中可以看出,我们一共上传了13张图片,其中图片服务器A保存了6张,图片服务器B保存了7张,两个服务器的负载并没有出现一头小一头大,而是一个相对比较均衡的数量,这得益于我们的随机函数。

  (3)测试图片文件浏览请求

  ①是否显示了图片列表:

  ②是否从不同图片服务器获取:

  总结:设立单独的图片服务器来专门存放图片后,把图片数据的流量从Web服务器上分离开,这样可以缓解Web服务器的I/O性能瓶颈,提高响应速度。

  (4)在原文的性能测试中,在局域网环境下对采用图片服务器和不采用图片服务器2种情况进行了性能测试:测试数据有300万张图片均匀分布在3台图片服务器上,每台图片服务器建立1 000个子目录。在5台客户端上同时运行压力测试软件,分别模拟200个~1 000个并发用户的请求。其测试结果如下图所示:

  从图中可以看出,采用3台普通PC机作为图片服务器后,整个系统的响应时间大大减少,性能得到明显提升,而且并发访问量越大,性能的提升越明显,而对于整个系统而言增加的硬件成本却很有限。

参考资料

   朱晓辉、王杰华、石振国、陈苏蓉,《海量图片的分布式存储及负载均衡研究》:http://www.cqvip.com/QK/71135X/201107/36101649.html

附件下载

  (1)数据库:MyImageServer.mdf

  (2)程序代码:MyImageDFS

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_822529.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SEO的艺术(原书第2版)

《SEO的艺术(原书第2版)》基本信息原书名&#xff1a;The Art of SEO, Second Edition作者&#xff1a; Eric Enge Stephan Spencer Jessie Stricchiola Rand Fishkin译者&#xff1a; 姚军丛书名&#xff1a; O’Reilly精品图书系列出版社&#xff1a;机械工业出版社ISBN&…

微软没强迫?Win 10 版本号追踪网站 Buildfeed 关闭

开发四年只会写业务代码&#xff0c;分布式高并发都不会还做程序员&#xff1f; 近日&#xff0c;迫于各方压力&#xff0c;知名 Windows 10 版本号追踪网站 Buildfeed 宣布关闭。对于 Windows Insider 用户来说&#xff0c;即时获取最新 Windows 10 预览版本信息很重要&…

开发小白也毫无压力的hexo静态博客建站全攻略 - 躺坑后亲诉心路历程

目录 基本原理方法1 - 本机Windows下建站 (力荐)下载安装node.js用管理员权限打开命令行&#xff0c;安装hexo-cli和hexo下载安装git初始化hexo使用hexo generate生成静态资源在本地运行hexo&#xff0c;看一切是否正常在Coding.net创建与用户名相同的项目&#xff0c;并启用代…

机器学习实战—k近邻算法(kNN)02-改进约会网站的配对效果

示例&#xff1a;使用k-近邻算法改进约会网站的配对效果 在约会网站上使用k-近邻算法&#xff1a; 1.收集数据&#xff1a;提供文本文件。 2.准备数据&#xff1a;使用Python解析文本文件。 3.分析数据&#xff1a;使用matplotlib画二维扩散图。 4.训练算法&#xff1a;此…

php微信用户绑定网站用户

php微信用户绑定网站用户实现原理&#xff1a;因为对于每个公共号&#xff0c;每个微信用户的open_id是固定不变的&#xff0c;也就是说可以利用网站用户id与微信用户的open_id建立一一对应关系。废话不多说&#xff0c;直接看代码&#xff1a; 数据库设计如下&#xff1a; 当…

JavaScript中mouseover和mouseout多次触发解决办法

问题描述 我希望当鼠标移动到id1上的时候&#xff0c;id2显示&#xff0c;当鼠标离开id1的时候&#xff0c;id2不显示。问题如下&#xff1a; 1.当鼠标从id1上移动到id2上的时候&#xff0c;id由有显示变为不显示&#xff0c;然后变为显示 2.当鼠标从id2上移动到id1上的时候…

怎样给自己的网站添加一个在浏览器标签、地址栏左边和收藏夹上显示的缩略logo标志

问题描述 不知道&#xff0c;大家有没有注意&#xff0c;有的网站&#xff0c;地址栏上都有一个小图标&#xff0c;如csdn或者是百度。 但是我个人做的网站就没有&#xff0c;怎样添加这样的图标呢&#xff1f; 其实&#xff0c;这个是通过favicon.ico来控制的。 favicon.ico…

当修改网站上的图片等资源时怎样避免客户缓存的问题

问题分析 最近在修改网站上的logo时候&#xff0c;发现修改后&#xff0c;浏览的时候&#xff0c;还是看到之前的图片&#xff0c;PC端多多刷新几次&#xff0c;显示倒是okey&#xff0c;可是手机端依旧是原图片。很明显是缓存的问题&#xff0c;但是我又不想清除手机浏览器缓…

在window中通过IIS发布自己的网站经验总结

转自&#xff1a;https://blog.csdn.net/YSG___/article/details/69061310?utm_mediumdistribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2.control&depth_1-utm_sourcedistribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2.c…

Win10下IIS配置、项目发布、添加网站

转自&#xff1a;https://study-life.blog.csdn.net/article/details/77006831?utm_mediumdistribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-7.control&depth_1-utm_sourcedistribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2…

内存泄露检查工具及相关网站

Visual Leak Detector http://xiaoruanjian.iteye.com/blog/1091410 灵活自由是C/C语言的一大特色&#xff0c;而这也为C/C程序员出了一个难题。当程序越来越复杂时&#xff0c;内存的管理也会变得越加复杂&#xff0c;稍有不慎就会出现内存问题。内存泄漏是最常见的内存问题之…

源码托管网站推荐——OKSvn

在团队开发时&#xff0c;没使用SVN或者其他版本控制工具必将带来很多不必要的麻烦。在本机搭建SVN的方法虽然可行&#xff0c;但你不能保证你的电脑一直处于运行状态&#xff0c;显然是很不方便的。 我们知道&#xff0c;新浪、谷歌都有项目托管&#xff0c;由于网速…

WordPress 在主题网站添加新年快乐红灯笼特效源码样式

在春节过年的时候看到有在WordPress博客网站添加了红灯笼新年快乐样式。很有过年气氛&#xff0c;今天就给大家分享一下具体的代码样式。 WordPress主题过节灯笼 CSS 样式 这个样式代码可以加在自己的主题 css 样式文件里&#xff0c;也可以单独写进去。部分 WordPress 主题&a…

网站变灰代码,一行代码让网站整体变灰,wordpress网站一行代码全站变灰教程

在遇到特殊情况的时候&#xff0c;我们作为站长需要紧急将网站变灰的需求&#xff0c;在此小编给大家总结了几种方法&#xff0c;通过简单修改一下站点样式即可实现。一段代码让网站整体变灰。这里主要介绍的利用 filter: grayscale属性来实现。供大家学习交流。 网站变灰代码…

WordPress插件 SuperPWA让你的WordPress网站瞬间变成APP

PWA 是 Progressive Web App 的英文缩写&#xff0c; 翻译过来就是渐进式增强 WEB 应用&#xff0c; 是 Google 在 2016 年提出的概念&#xff0c;2017 年落地的 web 技术。目的就是在移动端利用提供的标准化框架&#xff0c;在网页应用中实现和原生应用相近的用户体验的渐进式…

WordPress 网站怎么做会员中心功能【会员中心】

WordPress网站的会员后台与管理员后台默认是一样的&#xff0c;只不过功能少一些而已。但从整体版面上看&#xff0c;Wordpress 网站会员后台并不美观&#xff0c;很多站长并不喜欢这样的后台。那么对于使用 WordPress 建网站的站长&#xff0c;怎么样开发出一个版面美观的会员…

使用angular $interval服务实现购物网站秒杀活动时间倒计时

最近在做一个购物网站的秒杀活动,其中涉及到了一个时间的倒计时. 所谓“秒杀”&#xff0c;就是网络卖家发布一些超低价格的商品&#xff0c;所有买家在同一时间网上抢购的一种销售方式。通俗一点讲就是网络商家为促销等目的组织的网上限时抢购活动。由于商品价格低廉&#xf…

怎么扒站建站_深扒国内建站服务:网站建设哪家服务好?

企业如果想通过互联网来打响品牌&#xff0c;吸引更多客户&#xff0c;一个自己的官方网站是少不了的。如今各种建站服务商也有很多&#xff0c;但是服务质量良莠不齐&#xff0c;这该怎么选择呢&#xff1f;今天就跟大家深扒一下网站建设哪家服务好&#xff0c;让你明白企业到…

python与seo应用_python网络爬虫与SEO搜索引擎优化介绍

1. 什么是爬虫&#xff1f;首先应该弄明白一件事&#xff0c;就是什么是爬虫&#xff0c;为什么要爬虫&#xff0c;博主百度了一下&#xff0c;是这样解释的&#xff1a;网络爬虫(又被称为网页蜘蛛&#xff0c;网络机器人&#xff0c;在FOAF社区中间&#xff0c;更经常的称为网…

PHP网站留言要加验证码,php – 需要一些帮助来添加一些验证码联系表单

嗨,我是PHP的新手,我想要一些帮助.我已经创建了一个联系表单,我想添加一些验证码.我已经创建了一些gif图像,其中包含添加了一些噪音的数字,并将no1命名为code_01.gif,no2等命名为code_02.gif等.我已经将其中的一些设置在我的表单上,静态地用于显示目的,如此&#xff1a;我想添加…