NO END FOR LEARNING

Writing blog if you feel tired | 学海无涯 苦写博客

在Node下通过TravisCI部署由Gulp启动服务的应用到云平台Heroku

| Comments

这篇博客的起源比较有意思,客户给我们出了一道前端的开发题目,实现一个满足某种需求的web应用程序,算是某种程度的面试或者能力检测。

开发的技术栈采用我比较熟悉的:

环境:Node
脚手架,构建和依赖管理:Yoman,Gulp,Bower,NPM(Node包管理也算依赖管理吧)
开发框架:AngularJS,Bootstrap
测试框架和Runner:Karma,Protractor,Jasmine,Webdriver

当然还有些七七八八的JavaScript类库,这里就不罗列了。

开发时间大概用了不到一天,考虑到这些环境我都没安装,所以下载还是花了点时间的,基本的本地运行,单元测试,功能测试都完善了,本来想着已经差不多了,但作为一个在以构建,持续集成和持续交付自豪的公司(Build and CI is in our DNA)里工作的开发人员,好像还差点什么。

没错,就是持续集成和部署到PreProduction环境或者Production环境,之前没怎么用过Heroku,所以彻底完成还是足足花费了一天的时间,也就是从开发到上线用了两天,不过这其中踩了无数的坑。

关于开发以及构建的部分,我就不详细说明了,这与标题也不符合。

TravisCI

Alt text

Test and Deploy with Confidence Easily sync your GitHub projects with Travis CI and you’ll be testing your code in minutes!

TravisCI是一个免费的,可以和Github项目同步的持续集成服务器,对持续集成这个概念不懂的同学,请参考我司(我厂)高级咨询师腾云的翻译的Martin Fowler的文章《持续集成》 http://www.cnblogs.com/CloudTeng/archive/2012/02/25/2367565.html

其实,要使用TravisCI是非常简单的,假设你是Java的项目,且采用了Maven或者Gradle做构建,那么只需要在项目中添加一个.travis.yml的文件,在里面写上language: java,提交,并在TravisCI上将项目Sync打开,就可以开始构建了。可以参考资料: http://docs.travis-ci.com/user/languages/java/

但是在本例子中,采用的是Node环境,所以相对的配置就需要有所改变。基本配置和Java环境类似:

1
2
3
4
5
6
7
8
9
10
language: node_js
node_js:
  - "4.1"
  - "4.0"
  - "0.12"
  - "0.11"
  - "0.10"
  - "0.8"
  - "0.6"
  - "iojs"

这里要注意的是Node的版本,如果你使用4.0以上版本,很有可能在TravisCI上会遇到,导致npm install失败:

1
../node_modules/nan/nan.h:41:3: error: #error This version of node/NAN/v8 requires a C++11 compiler

官方文档上并没有给出解决这个问题的办法,唯一的临时解决办法就是使用低于4的稳定版本,比如我使用是0.12。

对于Node项目,TravisCI默认执行:npm test命令来运行你的测试(官方翻译:测试套件)。

如果你查看了官方文档,项目采用Gulp做构建,它会告诉你还需要在.travis.yml文件中添加:

1
2
3
before_script:
  - npm install -g gulp
script: gulp

如果添加script: gulp,TravisCI会运行gulp,而不会运行npm test命令,所以这里取决于你的项目构建(测试)运行方式。我这里采用的npm test,因为需要同时运行单元测试和功能测试,在我的配置中,gulp任务只是最优化打包应用,所以在.travis.yml我并没有这些配置。

官方参考文档: http://docs.travis-ci.com/user/languages/javascript-with-nodejs/#Using-Gulp

我的配置全部在package.json的Script中,主要原因是为了方便Heroku部署,这里之所以需要在npm install之后运行bower install是为了功能测试能够正常运行。

1
2
3
4
5
"scripts": {
    "test": "gulp test & gulp protractor",
    "start": "./node_modules/.bin/gulp serve:dist",
    "postinstall": "./node_modules/.bin/bower install"
}

到目前为止,TravisCI的配置就结束了,项目可以正常的在持续集成服务器(CI Server)上运行。

Heroku

Alt text

Heroku (pronounced her-OH-koo) is a cloud application platform – a new way of building and deploying web apps.

Heroku是国外有名的云应用平台,旗下的产品有:
Heroku Platform
Heroku Postgres
Heroku Redis
Heroku Connect
Heroku Enterprise

注册和安装Toolbelt

首先,你需要注册Heroku的账号,然后安装Heroku的Toolbelt工具。
可以参考: https://devcenter.heroku.com/articles/getting-started-with-nodejs#set-up

安装参考资料的提示,登录:

1
2
3
4
5
heroku login
Enter your Heroku credentials.
Email: zeke@example.com
Password:
...

在Travis中配置Heroku

登录Heroku创建一个应用程序,名字你自己取(得小写字母)

进入到应用,在Deploy的tab里面,你会看到一个Connect to Github,你可以选择将哪个repository和该应用关联来实现自动部署或手动部署,但TravisCI的自动部署跟它没有关系,所以你不用管它。

你要做的是看这里: http://docs.travis-ci.com/user/deployment/heroku/

在.travis.yml中配置:

1
2
3
4
5
deploy:
  provider: heroku
  api_key:
    secure: "YOUR ENCRYPTED API KEY"
...

虽然,你看得懂文档,但不建议手动配置,建议Travis和Heroku的客户端都安装,然后在项目目录下运行:travis setup heroku,来自动配置.travis.yml文件。

可以参考的文档: http://blog.travis-ci.com/2013-07-09-introducing-continuous-deployment-to-heroku/

配置完成之后,.travis.yml文件大概和下面的相似:

1
2
3
4
5
6
7
8
9
10
language: node_js
node_js:
- '0.12'
deploy:
  provider: heroku
  api_key:
    secure: QFSD0pnNddlsdZ6Wm/...
  app: yourapplicationname
  on:
    repo: benweizhu/yourApplicationRepoName

提交代码之后,TravisCI就会开始在构建完成之后,开始执行部署到Heroku。

这样就完了吗?错!!!前面已经踩过一些坑,但还不够坑。

现在正式开始采坑

执行完上面的步骤,你会发现构建是绿的,并且显示:

1
2
3
-----> Compressing... done, 65.3MB
-----> Launching... done, v28
       https://yourapplicationname.herokuapp.com/ deployed to Heroku

当你通过URL打开应用时,就会出现Application Error的页面。这个时候,就要开始troubleshooting了。

首先,你需要在TravisCI上构建和部署的log,这个就不用我教了。

如果TravisCI上没有问题,那么,你就需要查看Heroku服务器上的log,方法如下:

1
heroku logs --tail --app appname

所有的出现问题/导致失败的原因都可以在log中看到。

常见问题

问题1:Heroku的Node环境启动时,运行npm start,所以,你需要配置好,package中的script命令来正确的启动服务器。你也可以配置Procfile文件,那么它就会执行文件中的命令:

1
web: node node_modules/.bin/gulp serve:dist

问题2:Heroku没有在全局(global)下安装gulp,所以项目的gulp需要安装在本地,在npm start的命令中也要有相应的配置,比如:gulp命令是执行本地的bin目录。

问题3:Heroku会先运行npm install,所以如果项目使用了BowerJS,那么在postInstall要进行bower install。

问题4:确保package中,dependencies的配置是正确的,很多情况下,我们都把依赖放在了devDependencies中,但在产品环境下,应该在dependencies下。

问题5:端口号配置

一个Web dyno并需和传递给他的$PORT在60秒内绑定。

所以应用程序的端口配置应该:

1
2
3
// set the port of our application
// process.env.PORT lets the port be set by Heroku
var port = process.env.PORT || 8080;

Web Dynos: Web dynos are dynos of the “web” process type that is defined in your Procfile. Only web dynos receive HTTP traffic from Heroku’s routers.

另外还有一些问题:可能出在Heroku的配置上,具体请参考Heroku官方的troubleshootinghttps://devcenter.heroku.com/articles/troubleshooting-node-deploys#start-with-a-blank-slate

结束语

整个项目是一个完整的JavaScript全栈项目,从需求,到开发,最后部署,花费两天时间,虽然辛苦,但是学到不少东西。

参考资料:
1.http://docs.travis-ci.com/user/languages/javascript-with-nodejs/
2.http://docs.travis-ci.com/user/deployment/heroku/
3.http://www.sitepoint.com/deploying-heroku-using-gulp-node-git/ 4.http://www.hygkui.com/2015/03/13/%E4%BD%BF%E7%94%A8Gulp-Node-Git%E9%83%A8%E7%BD%B2%E9%A1%B9%E7%9B%AE%E5%88%B0Heroku%E4%B8%8A/ 上面的中文版
5.http://blog.travis-ci.com/2013-07-09-introducing-continuous-deployment-to-heroku/
6.https://devcenter.heroku.com/articles/troubleshooting-node-deploys#start-with-a-blank-slate

SEO实战密码:URL静态化

| Comments

URL静态化一直以来都是最基本的SEO要求之一,但近年来搜索引擎技术进步,抓取动态url已经不是问题,SEO行业对是否一定要做静态化也有了一些观念上的改变。

为什么要做静态化?

现在的网站绝大多数都是数据库驱动,页面由程序实时生成,而不是真的在服务器上有一个静态HTML文件存在。当用户访问一个网址时,程序根据URL中的参数调用数据库,实时生成页面内容。因此动态页面相对应的URL原始状态也是动态的,包含问号,等号及参数。

搜索引擎在发展初期,一般不愿意爬行和收录动态URL,主要原因是可能陷入无限循环或收录大量重复内容,造成资源极大的浪费。最典型的无线循环就是某些网站上出现的万年历。万年历会使得蜘蛛可以无限点击下去。

真实用户一眼就能看出这是一个万年历,但是搜索引擎蜘蛛面对的只是一串代码,不一定能判断它。

有时候就算不是无限循环,动态URL也可能造成大量重复页面。比如:想用的URL和参数(也就是相同的页面),但是参数的顺序不同(有多个参数)。

更麻烦的是,有时候某些参数完全可以是任意值,服务器都能够正常的返回某个固定页面。

这就是为什么搜索引擎对动态URL敬而远之的原因。

如何静态化URL呢?

最常见的方式是使用服务器URL重写模块,LAMP(Linux+Apache+MySQL+PHP)服务器上一般使用mod_rewrite模块,Windows服务器上也有类似的功能。

举例:

http://www.domain.com/products.php?id=123

静态化为:

http://www.domain.com/products/123

需要请用服务器模块mod_rewrite,然后在.htaccess文件写入代码:

1
RewriteRule /products/([0-9]+)/products.php?id=$1

URL重写基于正则表达式,每个网站的动态URL结构都不同,所以写起来就很麻烦。

严格的说,这里所说的URL静态化应该称为“伪静态化”,也就是说服务器上还是不存在相应的HTML文件,用户访问时还是动态生成页面,只不过通过URL重写技术使网站看起来像是静态的。当然,也有CMS系统可以实现真正静态化,系统会自动真实生成静态的HTML文件。但对于搜索引擎来说,真正的静态化和伪静态化没有区别。

到底是否需要URL静态化?

近年来搜索引擎对URL的抓取有了很大进步。一般来说,URL中有两三个参数,对于收录不会造成任何影响。权重高的域名,再多几个问号也不是问题。不过一般还是建议将URL静态化,即能提高用户体验,又能降低收录难度。

2008年9月,Google站长博客发表了一篇关于动态网址还是静态网址的帖子,颠覆了SEO界的观念。

Google的帖子有几个要点。

一是Google完全有能力抓取动态网址,多少个问号也不是问题。这一点基本靠谱。

第二,动态网址更有助于Google蜘蛛读懂URL含义,并进行鉴别,因为网址中的参数有提示性。比如Google举了这个例子:

www.example.com/article/bin/answer.foo?language=en&answer=3&sid=98971298178906&query=URL

URL里的参数都有助于Google理解URL及网页内容。比如language后面跟的参数是提示语言,answer后面跟的是文章编号,sid后面的肯定是session ID。其他常用的包括color后面跟的参数指的是颜色,size后面跟的参数是尺寸等。有了这些参数的帮助,Google更容易理解网页。

而将网址静态化后,这些参数的意义通常就变得不明显了。比如这个URL:

www.example.com/shoes/red/7/12/men/index.html

就可能使Google不知道哪个是产品序列号,哪个是尺寸等。

第三,网址静态化很容易弄错,那就更得不偿失了。比如通常动态网址的参数调换顺序,所得到的页面其实是相同的,比如这两个网址很可能就是同一个页面:

www.example.com/article/bin/answer.foo?language=en&answer=3

www.example.com/article/bin/answer.foo?answer=3&language=en

保留动态网址,Google还比较容易明白这是一样的网页。而经过静态化后,这样两个网址Google就不容易判断是不是同一个页面,从而可能引起复制内容:

www.example.com/shoes/men/7/red/index.html

www.example.com/shoes/red/7/men/index.html

再一个容易搞错的是session ID,也可能被静态化进URL:

www.example.com/article/bin/answer.foo/en/3/98971298178906/URL

这样网站将产生大量URL不同,但其实内容相同的页面。

所以,Google建议不要静态化URL。

虽然如此

但是《SEO实战密码》的作者建议还是做静态化。他认为Google的这个帖子解释的有些极端和牵强,也没有从其他搜索引擎的角度出发。

参考资料:
1.《SEO实战密码》