当前位置: 首页 > news >正文

新媒体网站建设十大的经典成功案例新旧网站对比

新媒体网站建设十大的经典成功案例,新旧网站对比,开通微信公众号要收费吗,装修公司做自己网站一、说明 构建一个微服务的电影网站#xff0c;需要Docker、NodeJS、MongoDB#xff0c;这样的案例您见过吗#xff1f;如果对此有兴趣#xff0c;您就继续往下看吧。 我们前几章的快速回顾 第一篇文章介绍了微服务架构模式#xff0c;并讨论了使用微服务的优缺点。第二篇… · 一、说明         构建一个微服务的电影网站需要Docker、NodeJS、MongoDB这样的案例您见过吗如果对此有兴趣您就继续往下看吧。   我们前几章的快速回顾 第一篇文章介绍了微服务架构模式并讨论了使用微服务的优缺点。第二篇文章我们讨论了使用 HTTP/2 协议的微服务安全性。本系列的第三篇文章描述了微服务架构中通信的不同方面我们解释了 NodeJS 中的设计模式如依赖注入、控制反转和 SOLID 原则。我们已经制作了 3 个 API并将其运行到 Docker 容器中我们已经进行了单元集成和压力测试。         如果你还没有读过前面的章节你错过了一些很棒的东西我会把链接放在下面所以你可以看看。 构建 NodeJS 影院微服务并使用 docker 部署【01/4】 构建 NodeJS 影院微服务并使用 docker 部署它02/4 构建 NodeJS 影院预订微服务并使用 docker 部署03/4 这是“构建 NodeJS 影院微服务”系列的第四篇文章。本系列文章演示如何使用 ES6、¿ES7 ...8连接到 MongoDB 副本集本文还演示了如何将其部署到 docker 容器中并模拟此微服务在云环境中的运行方式。 好的在这一点上我们将完成下一个图表 子影院微服务架构 notification.api.js hosted with ❤ by GitHub剩下的是为我们构建的是支付服务和 通知服务这次我们将非常快速地开发它们以专注于我们在此架构中没有讨论过的东西从一开始就存在API 网关所以请和我在一起让我们开始制作一些有趣的东西。 我们将在本文中使用的是 NodeJS 版本 7.5.0本地安装MongoDB 3.4.1Docker for Mac 1.13.0已安装1.13.1 破坏了东西 跟进文章的先决条件 已完成上一章中的示例。 如果你还没有我已经上传了一个 github 存储库所以你可以在分支步骤 3 上获得最新的存储库链接。 二、支付和通知服务         由于本文用于构建 API 网关因此这次我不会花太多时间来描述下一个服务我将只强调有趣的部分。对于此服务我们将继续使用相同的项目和应用程序结构对此会略有变化因此让我们看看此服务是如何组成的。 2.1 支付服务         要使支付服务正常工作您可能知道有一堆库供节点进行信用卡收费此时我将使用一个名为 stripe 的库但在构建我们的支付服务之前您应该访问 stripe 网站并创建一个帐户才能使用此库 因为我们需要一个条纹代币来进行支付测试。 # Then we need to install stripe in our project cinema-microservice/payment-service $ npm i -S stripe --silent         那么我们如何使用条纹首先让我们在我们的文件中注册我们的条纹依赖项di.js const { createContainer, asValue } require(awilix) const stripe require(stripe)// here we include the stripeSettings function initDI ({serverSettings, dbSettings, database, models, stripeSettings}, mediator) {mediator.once(init, () {mediator.on(db.ready, (db) {const container createContainer()container.register({database: asValue(db),validate: asValue(models.validate),ObjectID: asValue(database.ObjectID),serverSettings: asValue(serverSettings),// and here we register our stripe modulestripe: asValue(stripe(stripeSettings.secret))})mediator.emit(di.ready, container)}) // more code ..., check the cinema microservice repository for to see the full code 接下来我们将看到我们的文件如何api/payment.js use strict const status require(http-status)module.exports ({repo}, app) {app.post(/payment/makePurchase, (req, res, next) {const {validate} req.container.cradlevalidate(req.body.paymentOrder, payment).then(payment {return repo.registerPurchase(payment)}).then(paid {res.status(status.OK).json({paid})}).catch(next)})app.get(/payment/getPurchaseById/:id, (req, res, next) {repo.getPurchaseById(req.params.id).then(payment {res.status(status.OK).json({payment})}).catch(next)}) } 最后让我们检查一下我们的文件repository.js // this the function that makes the charge, when its done// returns the charge object returned by stripeconst makePurchase (payment) {return new Promise((resolve, reject) {// here we retrieve or stripe dependecyconst {stripe} container.cradle// we create the chargestripe.charges.create({amount: Math.ceil(payment.amount * 100),currency: payment.currency,source: {number: payment.number,cvc: payment.cvc,exp_month: payment.exp_month,exp_year: payment.exp_year},description: payment.description}, (err, charge) {if (err err.type StripeCardError) {reject(new Error(An error occuered procesing payment with stripe, err: err))} else {const paid Object.assign({}, {user: payment.userName, amount: payment.amount, charge})resolve(paid)}})})}// this the function that our API calls firstconst registerPurchase (payment) {return new Promise((resolve, reject) {// and here we call the function to execute stripemakePurchase(payment).then(paid {// if every thing is succesfull, we make the registry at our db, for the record onlydb.collection(payments).insertOne(paid, (err, result) {if (err) {reject(new Error(an error occuered registring payment at db, err: err))}resolve(paid)})}).catch(err reject(err))})}const getPurchaseById (paymentId) {... more code, where we only query our database for the payment with the id}// more code... visit the repository to see the complete code 我想在这里强调一些事情我们在这里使用一些指导方针就像我们一样优秀的开发人员在函数和 指导方针是repository.jsregisterPurchase()makePurchase() 做一件事DOT“每个函数应该只做一件事并尽可能做那一件事。 少即是多“F项应尽可能短如果它们运行的时间更长请考虑将子任务和数据分解为单独的函数和对象。 ——摘自《Programming Apps with Javascript》一书 埃里克·艾略特 2.2 通知服务         好的现在在我们的通知服务中再次有一些非常好的库用于发送电子邮件短信彩信等您可以查看twilio或sendgrid以更深入地了解通知服务但是这次我将向您展示一个非常简单的服务使用nodemailer。 # So we need to install nodemailer in our project notification-service$ npm i -S nodemailer nodemailer-smtp-transport --silent         现在让我们看看我们的js文件如何首先是我们的然后是我们的 api/notification.jsrepository.js module.exports ({repo}, app) {// this our endpoint where is going to validate our email, and the create and finally send itapp.post(/notifiaction/sendEmail, (req, res, next) {const {validate} req.container.cradlevalidate(req.body.payload, notification).then(payload {return repo.sendEmail(payload)}).then(ok {res.status(status.OK).json({msg: ok})}).catch(next)}) } notification.api.js hosted with ❤ by GitHub const sendEmail (payload) {return new Promise((resolve, reject) {const {smtpSettings, smtpTransport, nodemailer} container.cradleconst transporter nodemailer.createTransport(smtpTransport({service: smtpSettings.service,auth: {user: smtpSettings.user,pass: smtpSettings.pass}}))const mailOptions {from: Do Not Reply, Cinemas Company no-replaycinemas.com,to: ${payload.user.email},subject: Tickects for movie ${payload.movie.title},html: h1Tickest for ${payload.movie.title}/h1pCinem: ${payload.cinema.name}/ppRoom: ${payload.cinema.room}/ppSeats: ${payload.cinema.seats}/ppdescription: ${payload.description}/ppTotal: ${payload.totalAmount}/ppTotal: ${payload.orderId}/ph3Cinemas Microserivce 2017, Enjoy your movie !/h3}transporter.sendMail(mailOptions, (err, info) {if (err) {reject(new Error(An error occured sending an email, err: err))}transporter.close()resolve(info)})})}         要一如既往地查看完整配置欢迎您在分支步骤 4 的 github 上查看影院微服务存储库。 如果我们设置一切正常并运行集成测试我们的通知服务可以发送如下图所示的电子邮件 三、 结论 支付和通知服务         如果您认为我一如既往地使用这两项服务进行快速访问欢迎您向我发送推文或在下面发表评论以便我们可以更详细地讨论这里发生的事情。         有一件重要的事情我没有提到当我们用钱信用卡、账户处理时我们需要确保我们的数据被加密只是为了增加另一层安全性而在支付服务内部我们需要解密用户信息继续进行条纹结账。         最后在存储库中每个服务上都有我们的 bash 文件如果我们执行它我们会将我们的服务放入 docker 容器中。start_service.sh $ bash start_service.sh 如果我们在docker机器管理器1中运行它我们应该有这样的东西 码头工人容器列表 码头工人 PS :D 四、接口网关 迁移到微服务时应用程序设计和体系结构的最大变化之一是 使用网络在应用程序的功能组件之间进行通信。在整体式应用中应用程序组件在内存中进行通信。在微服务应用中这种通信是通过网络进行的因此网络设计和实现变得至关重要。— Nginx 互认协议文件 4.1 但首先¿什么是API网关¿ 我们需要它吗 API 网关是作为进入系统的单一入口点的服务器。它类似于面向对象设计中的立面模式。— 克里斯·理查森 API 网关封装了内部系统架构并为每个客户端提供了量身定制的 API。它可能具有其他职责例如身份验证、监视、负载平衡、缓存、请求整形和管理以及静态响应处理。 下图向我们展示了 API 网关如何适应我们的影院架构 影院微服务 API 网关示例 API 网关负责请求路由、组合和协议转换。来自客户端的所有请求首先通过 API 网关。然后它将请求路由到相应的微服务。 4.2  我们为什么需要它优点和缺点         因为使用 API 网关封装了应用程序的内部结构这减少了客户端和应用程序之间的往返次数并且还简化了我们的代码。实现 API 网关以两种方式之一处理请求。某些请求只是代理/路由到相应的服务。它通过扇出到多个服务来处理其他请求。         但是 API 网关也有一些缺点。它是另一个“必须开发、部署和管理的高可用性组件”。还存在 API 网关成为开发瓶颈的风险因此作为优秀的开发人员我们必须更新 API 网关更新 API 网关的过程必须尽可能轻量级。 跨领域关注点的实现方式必须使微服务无需处理有关其特定范围之外的问题的详细信息。例如身份验证可以作为任何 API 网关或代理的一部分实现。— authO         API 网关处理的常见问题列表 认证运输安全负载平衡请求调度包括容错和服务发现依赖关系解析传输转换 五、构建微服务         好的现在我们已经湿透了我们已经阅读了 API 网关的功能让我们开始构建我们的影院微服务 API 网关         在知道我们一直在使用 http/2 协议构建微服务之前为了启动和运行该协议我们需要满足一些规则我们需要创建一些 SSL 证书为了简单起见我们创建了自签名证书但这将成为在我们的 API 网关中代理我们的路由的问题。http-proxy nodejs 模块有一个建议告诉我们以下内容 您可以在选项中设置安全 SSL 证书到目标连接避免自签名证书的验证。secure: true         我们不能将代理为自签名证书我们需要将微服务 HTTP/2 协议回滚到前一个协议但并非一切都是坏消息因为 API 网关有很多问题我们现在将使用 HTTP/2 协议仅在 API 网关中这就是我们如何激活网关的传输安全问题。         那么让我们开始吧让我们开始动手一些编码/‍‍但首先我们需要进行一些审查并查看我们的微服务定义这在我们的raml中文件然后我们需要检查我们的 api 文件并确认我们的 api 路由定义良好。这很重要因为这些路由是我们要代理的路由。         因此让我们从raml files booking.raml hosted with ❤ by GitHub #%RAML 1.0 title: Booking Service version: v1 baseUri: /booking/:type: { POST: {item : Booking, item2 : User, item3: Ticket} }/verify/{orderId}:type: { GET: {item : Ticket} } view rawcatalog.raml hosted with ❤ by GitHub #%RAML 1.0 title: Cinema Catalog Service version: v1 baseUri: /cinemas/:type: { GET: {item : Cinemas } }/{cinema_id}:type: { GET: {item : Movies } }/{city_id}/{movie_id}:type: { GET: {item : Schedules } }movies.raml hosted with ❤ by GitHub #%RAML 1.0 title: Movies Service version: v1 baseUri: /movies/:/premieres:type: { GET: {item : MoviePremieres } }/{id}:type: { GET: {item : Movie } } notification.raml hosted with ❤ by GitHub #%RAML 1.0 title: Notification Service version: v1 baseUri: /notification/sendEmail:type: { POST: {item : Payload} }/sendSMS:type: { POST: {item : Payload} } payment.raml hosted with ❤ by GitHub #%RAML 1.0 title: Payment Service version: v1 baseUri: /payment/makePurchase:type: { POST: {item : PaymentOrder} }/getPruchaseById/{orderId}:type: { GET: {item : Payment} }         因此现在我们已经很好地定义了端点是时候重构我们的微服务了仅使用 http 协议并在代码中检查我们的 api 端点。 现在看最有趣的部分还没有到来         由于我们一直在对我们所有的微服务进行码头化因此知道哪些容器正在运行 并且如果我们发出以下命令docker-machine manger1 $ docker inspect containerName | containerId         这将返回我们有关该容器的作用的信息前提是我们在容器创建时刻指定该信息如果您一直在关注本系列您已经注意到每个服务都有一个 所以现在我们需要停止并删除我们的服务为什么因为我们要在标签标志中添加一个新标志如下所示start-service.shdocker run command. $ docker run --name {service} -lapiRoute{route} -p {host-port}:{container-port} --env-file env -d {service}         让我们看看为什么我们需要这个标志为此我的朋友们让我们深入了解 api-gateway 源代码所以我们要看到的第一个文件是api-gateway/config.js const fs require(fs)const serverSettings {port: process.env.PORT || 8080,ssl: require(./ssl) }const machine process.env.DOCKER_HOST const tls process.env.DOCKER_TLS_VERIFY const certDir process.env.DOCKER_CERT_PATHif (!machine) {throw new Error(You must set the DOCKER_HOST environment variable) } if (tls 1) {throw new Error(When using DOCKER_TLS_VERIFY1 you must specify the property DOCKER_CERT_PATH for certificates) } if (!certDir) {throw new Error(You must set the DOCKER_CERT_PATH environment variable) }const dockerSettings {protocol: https,host: machine.substr(machine.indexOf(:, 0) 3, machine.indexOf(:, 6) - 6),port: parseInt(machine.substr(-4), 10),checkServerIdentity: false,ca: fs.readFileSync(certDir /ca.pem),cert: fs.readFileSync(certDir /cert.pem),key: fs.readFileSync(certDir /key.pem),version: v1.25 }module.exports Object.assign({}, { serverSettings, dockerSettings })         在这里我们设置 docker-settings 变量因为我们将与我们的通信但为了能够与该机器通信我们需要将我们的环境正确设置为 manger1 docker 机器我们可以在我们的终端中执行此操作执行以下命令manager1 docker-machine $ eval docker-machine env manager1         一旦设置了我们的环境我们将直接从nodejs连接到我们的docker-machie为什么因为我们正在获取正在运行的容器的信息并且能够正确地将请求从我们的 API 网关代理到微服务。         那么我们如何从nodejs连接到我们的docker机器首先我们需要安装一个调用到我们项目的nodejs模块如下所示dockerode $ npm i -S dockerode --silent         在我们继续查看 API 网关的代码之前首先让我们弄清楚什么是代理。 在计算机网络中代理服务器是充当客户端请求的中介的服务器这些请求从其他服务器寻求资源。— 维基百科         好的现在让我们看看什么是 ES6 代理。 代理是 ES6 中一个有趣而强大的功能它充当 API 使用者和对象之间的中介。简而言之每当访问基础对象的属性时都可以使用 来确定所需的行为。对象可用于为您的 配置陷阱这些陷阱定义和限制访问底层对象的方式 — 来自《实用 ES6》一书作者尼古拉斯·贝瓦夸ProxytargethandlerProxy 因此现在我们知道代理在计算机网络中和作为 ES6 对象的含义让我们看看docker.js 在我们的文件中发生了很多魔术✨所以让我们看看发生了什么。docker.js use strict const Docker require(dockerode)const discoverRoutes (container) {return new Promise((resolve, reject) {// here we retrieve our dockerSettingsconst dockerSettings container.resolve(dockerSettings)// we instatiate our docker object, that will communicate with our docker-machineconst docker new Docker(dockerSettings)// function to avoid registering our database route and api route const avoidContainers (name) {if (/mongo/.test(name) || /api/.test(name)) {return false}return true}// here we register our routes in our ES6 proxy objectconst addRoute (routes, details) {routes[details.Id] {id: details.Id,name: details.Names[0].split().splice(1).join(),route: details.Labels.apiRoute,target: getUpstreamUrl(details)}}// we generate the container url to be proxyconst getUpstreamUrl (containerDetails) {const {PublicPort} containerDetails.Ports[0]return http://${dockerSettings.host}:${PublicPort}}// here we list the our running containersdocker.listContainers((err, containers) {if (err) {reject(new Error(an error occured listing containers, err: err))}const routes new Proxy({}, {get (target, key) {console.log(Get properties from - ${key} container)return Reflect.get(target, key)},set (target, key, value) {console.log(Setting properties, key, value)return Reflect.set(target, key, value)}})containers.forEach((containerInfo) {if (avoidContainers(containerInfo.Names[0])) {addRoute(routes, containerInfo)}})// and finally we resolve our routesresolve(routes)})}) }module.exports Object.assign({}, {discoverRoutes})         因此首先我们实例化我们的对象以便能够与我们的 docker 机器通信然后我们创建我们的来存储我们的对象发现的所有路由并列出它然后我们遍历发现的容器并使用容器详细信息注册我们的 对象这就是为什么我们需要在启动 docker 容器时添加标签标志因为它可以为我们提供更多信息而这种操作系统是向容器添加信息的一种方式因此对我们来说它可以帮助我们了解容器的用途。dockerproxy routes objectdockerroute 所以最后我们解析或路由对象在 .你可能会问我为什么使用 ES6 代理对象这是因为我认为这可能是使用 ES6 代理对象的一个很好的例子因为我还没有看到很多 ES6 代理的例子我们可以使用任何类型的对象来存储我们的路由但代理对象可以帮助我们做更多的事情 我们可以在 JavaScript 对象中看到中间件等代理但这超出了本文的范围。server.js 所以现在让我们看看我们的文件看看我们如何实现我们的路由server.js use strict const express require(express) const proxy require(http-proxy-middleware) const spdy require(spdy) const morgan require(morgan) const helmet require(helmet) const cors require(cors) const status require(http-status)const start (container) {return new Promise((resolve, reject) {const {port, ssl} container.resolve(serverSettings)const routes container.resolve(routes)if (!routes) {reject(new Error(The server must be started with routes discovered))}if (!port) {reject(new Error(The server must be started with an available port))}const app express()app.use(morgan(dev))app.use(bodyparser.json())app.use(cors())app.use(helmet())app.use((err, req, res, next) {reject(new Error(Bad Gateway!, err: err))res.status(status.BAD_GATEWAY).send(url not found!)next()})for (let id of Reflect.ownKeys(routes)) {const {route, target} routes[id]app.use(route, proxy({target,changeOrigin: true,logLevel: debug}))}if (process.env.NODE test) {const server app.listen(port, () resolve(server))} else {const server spdy.createServer(ssl, app).listen(port, () resolve(server))}}) }module.exports Object.assign({}, {start})         在这里我们要做的是创建一个然后我们循环我们的路由并将其注册到应用程序中作为中间件在该中间件中我们正在应用另一个称为将请求代理到正确的微服务的中间件最后我们启动我们的服务器。express apphttp-proxy-middleware         所以现在我们已经准备好在本地运行我们的 api-gateway 并运行超级集成测试我们将调用 raml 文件中声明的所有端点并通过 api-gateway 调用它。         但首先让我们重新创建我们的容器为此让我们创建一个名为的自动化脚本该脚本为我们完成所有工作如下所示start_all_microservices.sh #!/usr/bin/env basheval docker-machine env manager1array(./movies-service./cinema-catalog-service./booking-service./payment-service./notification-service )# we go to the root of the project cd ..for ((i 0; i ${#array[]}; i)); do# we go to each foldercd ${array[$i]}sh ./start-service.sh# and we go back to the root again :Dcd .. done         但是我们需要使用新的标签标志修改每个微服务如下所示start-service.sh docker run --name booking-service -lapiRoute/booking -p 3002:3000 --env-file env -d booking-service docker run --name catalog-service -lapiRoute/cinemas -p 3001:3000 --env-file env -d catalog-service // and so on # and once we have it, lets run the command $ bash start_all_microservice.sh 我们需要有这样的东西         带有新标签标志的新容器和新创建的容器以便能够在我们的nodejs api-gateway中发现它所以现在让我们使用以下命令运行我们的api-gateway $ npm start         这将在我们的“没有类似的地方”中启动一个服务器127.0.0.18080我们心爱的本地主机我们应该看到这样的东西 API 网关控制台输出         接下来我们需要打开另一个终端并将其放置在我们的影院微服务项目中并运行以下命令来执行我们的超大型集成测试 $ npm run int-test         我们将有一些如下所示的输出         在上控制台中我们可以看到代理如何调度并重定向到相应的urlport在下控制台中我们可以看到所有测试是如何正确通过的。         我们需要对我们的 api-gateway 做一件事那就是 dockerize 我们的 api-gateway但让我告诉你我无法 dockerize 它我还在弄清楚如何从容器到 docker-machinehost说话如果你能弄清楚欢迎你在下面发表评论 与我们分享您发现并应用于Dockerize我们的API网关的内容因此与此同时我仍在研究如何完成此任务因此这就是为什么我们在“没有像127.0.0.1这样的地方”地址而不是Docker机器IP地址中进行集成测试的原因所以请继续关注我会告诉您我所发现的。 六、更新  API 网关docker化解决方案         再次您好让我告诉您我发现了什么以及如何解决此问题因此让我们开始对 API 网关进行 docker化。         因此按照我们的模式让我们看一下我们的内部 api-gateway 文件夹这个文件应该包含这样的内容start-service.sh #!/usr/bin/env bash eval docker-machine env manager1 docker rm -f api-gateway-service docker rmi api-gateway-service docker image prune docker volume prune docker build -t api-gateway-service . docker run --name api-gateway-service -v /Users/Cramirez/.docker/machine/machines/manager1:/certs --nethost --env-file env -d api-gateway-service 在这里我们添加了一些标志所以让我们看看它们。 卷标志 在这里我们将 docker 机器证书文件夹绑定到我们的容器以便它能够读取这些证书-vnet 标志在这里我们告诉容器连接主机网络适配器这会将 docker 机器 IP 绑定到我们的 API 网关容器我们唯一需要关心的是可用的端口以便我们可以运行我们的 API 网关就我而言我正在端口 8080 上执行 API 网关--net 所以现在我们可以再次调用我们的超级骗子测试但知道我们的 docker 机器 ip api 网关端口例如https://192.168.99.100:8080 七、是时候回顾一下了         我们做了什么... 我们总结了下图         我们在本文中只构建了 3 个服务支付服务、通知服务和超级骗子 API 网关 .         我们已经集成了微服务的所有功能所以现在我们可以发出 GET 和 POST 请求在这些请求中我们的一些微服务具有数据验证、数据库交互、第三方服务交互等......总而言之我们已经做了很多工作但让我告诉你亲爱的读者这不是该系列的结束也许这可能会开始像权力的游戏一样没有结局冬天来了❄️对我来说很多电视节目但与我们的电影微服务系统有很大关系 所以请继续关注一些有趣的东西。         我们通过 API 网关实现了什么         我们提供微服务安全性仅在我们的API网关服务器中处理这称为传输安全性 ✔️         我们做了一个半动态的容器服务发现为什么是半因为我们使用添加到容器中的 label 标志对路由进行硬编码并且我们一个接一个地创建容器但这有助于我们将请求重定向到正确的目标这称为请求调度✔️和依赖关系解析 ✔️         我们已经在 NodeJS 中看到了很多开发但我们可以做和学习的东西还有很多这只是更高级编程的先睹为快。我希望这已经展示了一些有趣和有用的东西你可以在你的工作流程中用于Docker和NodeJS。
http://www.dnsts.com.cn/news/51377.html

相关文章:

  • wordpress中文版下载地址佛山百度seo代理
  • 网站推广哪种方法最企业管理系统软件开发
  • 建设网站平台费设计网站公司哪里好
  • 上海小学网站建设招标电器 东莞网站建设
  • 南乐县住房和城乡建设局网站广东线上营销推广方案
  • 站长推广网四川建设招投标网站
  • 长沙企业网站开发怎样建网站步骤
  • 管理网站用什么系统好大连网站建设开发
  • 给别人做网站多少钱国家级示范职业学校 建设网站
  • 天猫优惠券网站怎么做网站建设所需人力时间
  • 什么网站可免费发布信息自己做的网站如何让百度收录
  • 普陀酒店网站建设深圳软件外包公司都有哪些
  • 电子商务网站规划、电子商务网站建设万网域名注册官网gname
  • 做网站的教程贸易类文章网站
  • html演示网站广州电玩网站开发
  • 大英县住房和城乡建设局网站做网站 网络映射
  • 移动端网站开发最好的环境wordpress怎么采集淘宝客
  • 网站界面排版合肥建设信息网站
  • 西安网站制作首页wordpress升级php7.1
  • 长丰网站建设企业网站开发怎么样
  • 集团网站建设哪家更好wordpress米表插件
  • 推荐电商网站建设移动wap是什么意思
  • 个人网站好备案吗wordpress 网易云音乐
  • 国外前端 网站404页面模板
  • 免费永久个人网站注册网站专题页面文案设计
  • 上海小程序开发公司哪家好?青岛seo推广专员
  • 陕西建设部网站官网wordpress手机版论坛
  • 杭州建设项目审批网站兰州网络推广制度
  • 网站制作 wordpress广州网站建站平台
  • 表格在网站后台是居中可到前台为什么不居中重庆中色十二冶金建设有限公司网站