首页 > 代码库 > 一个小型线上网站的产生历程
一个小型线上网站的产生历程
自学了一段时间web开发后面试了份全站实习工作(就是前后端包括服务器搭建都一个人完成)。然后就开始了第一次真实搭建一个线上运营的网站的历程...
整个网站包括6个可显示页面,其中3个为动态生成页面。由于是企业的一个业务使用网站(就是用户通过登录我们网站使用公司提供的某项业务),不涉及支付,涉及的数据库表规模和实际日访问量都不会太大,此外涉及一个用调用实际业务代码(C代码)的问题。
前后我的主要开发时间大概是2周,2周后我基本已经闲着在关注安全问题和做些小改善了...所以估计出来的网站还是比较粗糙的,不过实战的过程中确实会遇到很多之前自己瞎鼓捣不会遇到的问题,于是也便趁解决之机学到了不少,在此做一个历程总结,希望对新手有用,也诚望高手赐教!
由于算新手,掌握或者说用过的东西只包括html/css,js,php,python,mysql,apache,但是对各种框架完全不熟悉,第三方插件里也只用过jquery和phpmyadmin,所以整个搭建思路很简单,前端html/css+js/jquery搞定,后端典型的lamp加上postfix作为邮件发送服务器,此外由于boss比较喜欢qq邮箱的自动提示(其实就是发提示到微信端= =)功能,所以接收邮件这个功能是通过腾讯域名邮箱功能搞定的(可以登录domain.mail.qq.com按着步骤做,腾讯的提示还是足够的,原理基本上就是修改dns里的mx记录(该记录决定了指定域名的邮件服务器ip地址)使得其他人发送以指定域名结尾的邮件时会发送到腾讯的服务器上)。
交代完背景后下面我们先来开始云服务器的搭建历程。
先解决物理服务器问题:使用的是阿里云的云服务器,而且我们在测试阶段申请的是1G1核6个月免费那种,带宽是1M,ubuntu 12.04系统(好像大家都推荐centos,不过小网站为了方便安装各种东西而且ubuntu其实稳定性还行啦),然后用cat /proc/cpuinfo 命令可以看到阿里云使用了Intel(R) Xeon(R) CPU E5-2630 0 @ 2.30GHz 的处理器还是很良心的(想想我这六个月免费用然后它给我个至强E5-2630)后来跑压力测试(见http://www.cnblogs.com/yjf512/archive/2011/05/24/2055723.html)的时候发现这样的配置每秒可以处理12个请求,但是我觉得主要瓶颈是带宽的限制,在服务器上使用top命令可以看到峰值时cpu的空闲率在80%以上,内存大概剩余200M的free,而我在测试发起端看到Transfer rate: 128.09 [Kbytes/sec] received,1M的带宽下载速度一般按1/5算峰值,也差不多了。
阿里云免费的是需要写申请的等审批通过不想免费直接买了就可以现用(当然企业用途的后面阿里云会有备案程序招呼你,boss被迫在阿里云寄的背景布前留下了一张“挺sb”(boss原话)的照片),当然域名是boss先在万网上买好的,修改dns记录绑定服务器的公网ip也是在上面搞定。(为新手补充下知识:dns中的a记录为正向域名解析,决定类别人访问你绑定的这个域名时域名会先映射成哪个服务器的ip,然后实际最后都是根据ip找到服务器位置来获取网页内容,绑定的域名可以指定前后缀,所以完全可以同一个域名,但前缀不一样访问的服务器也不一样(eg.a.xxx.com,和b.xxx.com分别指向121.5.5.5和121.5.5.6两个不同的ip)),在万网上修改一个dns记录后全球同步时间大概10分钟,还是挺给力的(同步后别人才可以通过这个域名访问你的服务器,否则只能通过直接的ip访问)。
服务器和域名绑定问题解决后开始服务器上的应用环境搭建工作了。ubuntu自带python,所以主要是apache,postfix,php,mysql还有phpmyadmin(一个基于php的web端mysql数据库管理工具)的安装和配置,由于我比较懒,所以选服务器的适合是直接在阿里云上选了个镜像(就是一个别人已经安装配置好的操作系统)配上去(http://market.aliyun.com/imageproduct/16-122106003-jxsc000020.html?spm=5176.6883001.0.0.4yKKwv上面已经集成了php apache mysql还有phpmyadmin),不过如果用这个镜像的话记得要在前面那个页面中下载它的使用指南,不然就和我一样一开始得自己去搞明白它的目录结构了...不过最后我还是因为要解决一个安全问题(php-cgi的query strng注入可执行代码漏洞)得自己重新去编译安装新版的php5.6(镜像自己配的是5.2版的,这个漏洞要解决得自己给php5.2的源码打补丁后重新编译安装——既然如此,不如直接编译安装php5.6好了,5.3和5.4的某个版本后已经把那个漏洞补上了~)
此外,使用镜像的好处是它在安全上也提供了很好的预先配置,比如linux的权限设置(owner-group-other),镜像都做了到位的设置,如果不使用镜像的话很多文件夹的权限都得自己去修改以提高安全性。然后,apache的httpd.conf文件,php的php.ini文件,mysql的my.cnf这三个配置文件也基于安全和并发量控制做了很多预先的设定,这些东西自己学的话需要查阅不少文档,所以省事的办法还是使用镜像,然后再通过一些安全检测工具(有很多这样的站长工具,比如360家的)看看镜像上还存在什么漏洞,把漏洞补了,再在代码级上防止sql注入攻击和做好必要的过滤验证(使用session保持会话验证状态,正则表达式过滤非法数据等),架构上对sql的用户权限做一些限制(比如用专门的账户作为脚本运行时使用的账户,然后只给予所需的最低权限,如只给增查改),感觉差不多对于一个不涉及支付的网站这样的安全程度就足够了(唔,还请高手们指正)。
至于打算从头开始的,可以参考http://www.cnblogs.com/lynch_world/archive/2012/01/06/2314717.html 安装php mysql apache phpmyadmin,或者你对安装路径有特殊要求的可以各个官网下载源码包查阅相关编译参数后编译安装。然后安全上的配置就得自己从头捣鼓了。
至于邮件服务器postfix,参考http://blog.csdn.net/bird_wang/article/details/4225113进行安装和配置
然后通过php的mail函数即可发送邮件。至于是发送纯文本还是要发送html编码的邮件以及如何加入邮件头部请搜索mail函数的用法即可。
在我这个网站里邮件的主要作用是用于用户找回密码时发送验证链接。此外发现一个比较奇怪的现象,php里发送邮件时插入换行符是使用\n,但是为了使他生效笔者发现需要字符串使用双引号扩起来
eg."用户您好:\n"换行有效而‘用户您好:\n’换行无效...
实际的开发中往往需要ssh登陆的服务器上进行操作,使用scp传递文件,这两个命令的介绍资料挺多的可以百度得到。此外,传递文件的另一种方式是建立ftp服务器的服务器端并在自己的电脑上安装filezilla等ftp客户端软件,这样可以实现图形界面的文件上传(还支持批量)。服务器端可以使用Pure ftp(参见http://www.cnblogs.com/ventry/archive/2012/06/04/2534444.html)
然后是实际的前后端代码的编写
由于是公司的网站,不可以开源,所以后面的内容主要以总结性的经验形式出现...
先解决开发工具的问题
前端的高富帅开发工具——webstorm强烈推荐,能够编辑html,css,js代码,同时支持各种高亮和提示(特别是支持jquery提示),用它开发前端一个字“爽”。下载安装自行到官网(http://www.jetbrains.com/webstorm/),然后可以试用30天(于是够我这次的开发了),实在想长期用的话网上有共享出来的注册码,当然还是希望大家支持正版。
后端的话我用的是vim,因为php和python都是脚本语言,不用编译,然后vim用于代码定位以及增删查改等效率上的优势还是比较明显的。以及小型web开发,也不像编什么算法题一样需要经常看某个变量的值,实在需要的适合加个输出语句编辑完一跑就知道了。(其实本质原因还是eclipse用得不熟悉?)
然后服务器上有什么肯定本地就得跟着有什么,大部分的开发调试工作一般都是在本地做的(所以前面那个安装php mysql..的帖子还是派上了用场),而到服务器上时可能就会发现在本地好好的代码上去就各种问题...
下面列举几个在本地和服务器端遇到的问题:
1.解决apache上访问 cgi脚本时总是在网页中显示出脚本的源代码而不是执行结果的问题
2.python 在使用MySQLdb模块时报Can‘t extract file(s) to egg cacheThe following error occurred while trying to extract file(s) to the Python eggcache的错误。
(python要和mysql交互可以通过MySQLdb这个模块(可以参考http://www.cnblogs.com/rollenholt/archive/2012/05/07/2487137.html,比较新的版本的MySQLdb安装前还需要机器上有安装setuptools,百度解决即可))
3.启动mysql时显示:/tmp/mysql.sock 不存在的解决方法
其他的问题也许因为我没遇到或者因为比较常见就不一一列举了,有其他问题的朋友可以留言与我讨论。
接下来探讨某些后端功能的实现方式:
1.会话状态的保持
对会话状态的保持有两个作用,一个用于防止用户访问需要登录之后才能访问的页面,一个是已登录用户访问首页时自动跳转到已登录页面。
实现这个功能的主要方式是session,session的原理是在服务器端保存session数据,而在客户端保存session数据的id(一般是保存在cookie里),客户端向服务器发起访问时服务器通过id来取出对应的session数据(但注意php的默认session保存时间是24分钟,如果在第一次请求后24分钟内客户端没有发起第二次请求,则session会被服务器清空)。
php中session的使用
因此可以在登录脚本中为已登录用户设置$_SESSION[‘logined‘]=true;然后对每个需要检验登录状态的网页(.php文件)在开头加入一段php代码用于检验$_SESSION[‘logined‘]是否已经设置(通过isset函数来检查,不检查直接访问一个空的数组位置会报错)以及是否为true
<?phpif(!(isset($_SESSION[‘logined‘])&&$_SESSION[‘logined‘]==true)){ header("location: index.php");
exit(‘1‘); }?>
这样如果未登录的用户打算通过url直接访问该页面时就会自动发生跳转,注意,header("location: index.php"); 语句必须在所有输出语句之前才能实现跳转功能(跳转目的为location: 后面指示的文件),此外,最好养成每个跳转语句后接上exit();语句(参数可以自己选,只作为退出时的返回值)以退出该脚本的执行,否则,尽管用户通过浏览器无法看到该页面内容(因为跳转到了另一个页面),但是如果采用网络抓包工具,上述php代码后面的内容(或者说执行结果)仍然可以被捕获(因为仍然发送到了客户端),而这往往不符合程序的设计意图。
2.线程安全地获取插入mysql的条目的id
3.对用户密码的保存处理
一般我们不应当保存明文的用户密码,除了涉及用户密码隐私外,在网站被入侵的情况下,明文的密码无疑正中黑客的下怀。
一种做法是保存多次md5加密的结果,由于md5不可逆,唯一的破解方式也是通过一个字典来暴力破解,因此经过多次md5加密后的结果具有较可信的安全度。php中md5的使用方式很简单,md5(md5($variable))返回的就是$variable两次加密后的结果,此外,md5得到的结果是32位字符(也可能是16位),这也为存放密码的空间提供了上限。
4.正则匹配过滤非法输入
在网络上,我们不能假设用户传回来的数据一定满足我们本来设定好的格式和内容要求,比如在正常使用网页时,也许我们在否次数据通信中在网页代码里通过js的ajax发送回来一个整数类型的数据,然后在脚本中我们根据这个整数进行处理。但实际上,用户可以操纵往服务器发送的数据,包括get,post等各种方式所传递的数据,对于黑客,这些数据中往往还包含可以入侵的代码,如果不对取得的数据加以验证就直接进行使用,无疑于把自己完全暴露在这些入侵代码之下。
因此一种过滤方式就是采用正则匹配来过滤,正则表达式的相关资料比较多可以自行查找,而php中使用正则表达式有两类库,一类是preg开头的一类是ereg开头的,其中ereg开头的遵守POSIX正则表达式规范(可以参见http://blog.csdn.net/echo_qiang/article/details/5907679正则表达式在不同的规范中有所不同,特别是一些转义字符)。在使用中,preg库常用于从一段字符串中提取匹配的子串,而ereg可用于检验整个字符串是否匹配特定的正则表达式。
我在开发中使用的是ereg库,因为ereg函数十分简单地满足了我的需求
bool ereg(pattern,target) //pattern为正则表达式字符串,target为想要检查是否匹配的字符串,若匹配函数返回true,否则为false
比如我想检查post传输的数据id是不是数字串,ereg("^[0-9]+",$_POST[‘id‘])即可。
5.防止sql注入攻击
sql注入攻击一般发生于执行sql语句的时候,比如,mysql_query(‘select * from table1 where id = ‘.$_POST[‘id‘]); 由于mysql是以特定字符为一个sql语句的分隔符的,如果黑客在id数据里插入这么一个符号后在后面就可以随便加入他想执行的sql语句了,这种执行轻则毁坏数据表,重则破坏系统或盗取系统用户信息,所有对于有数据库交互的网站放置sql注入攻击是必要的。(所有我们会发现前面的正则匹配过滤的重要性,但同时我们也会发现,有时还无法预估用户的输入应该是什么(比如如果你在网页中放置了一个留言板等),那么这种情况下无法使用正则匹配来过滤)
一种方式是对哪些特殊的分隔符进行转义,使用php的mysql_real_escape_string函数可以达到对传入的字符串进行转义的效果,一般而言,这样的转义已经足够。
但更正规的做法是采用一种称为动态参数绑定的方法。
我们会发现,发生sql注入的原因是因为我们在动态生成一条sql语句时使用了字符串的拼接,而由于特定分隔符的存在,这样的拼接总是漏洞重重,而实际上,我们需要的动态生成sql语句的动态程度只是希望某些参数可以动态给定,所有实际上只要能规定只修改这个参数的内容而不影响sql语句的其他部分即可达到防止sql注入攻击的目的(就算黑客打类一长串sql注入代码进来我们也只是把它当作普通数据存起来而不是去执行它)。
php的mysqli_stmt类就满足了动态参数绑定的要求,可以参考http://book.51cto.com/art/200909/154027.htm和http://blog.sina.com.cn/s/blog_0ee72b370101bmlo.html
唯一的缺陷是目前这个类在获取执行结果时不支持参数数组(不像mysql_fetch_array($result,MYSQL_ASSOC);传入MYSQL_ASSOC参数后即可得到一个参数数组),只能按照顺序逐个绑定结果存放变量。如果有高手知道其他的支持动态参数绑定又支持返回参数数组结果的方法麻烦赐教!
后端的问题好像说得七七八八了,如果有什么其他希望探讨的也欢迎留言!
下面进入前端,一个我觉得变化万千的新世界:
前端的实现在我看来是一个充满灵活性的世界,一种效果可能有很多种实现方式,而这些实现方式可能涉及运行性能,后期可维护性及扩展性(如MVC模型编程,面向对象思想等),web语义等诸多方面的考量,当然,对于像我一样的刚入门者可能还是以能实现一个功能为目的。
1.html/css实现阴影蒙版覆盖原网页并显示浮框的功能
2.jquery监听input元素输入
3.position:relative的用法
实践过程中发现position:relative的使用可以完成很多效果设置和对某些细微定位的改善。
比如有时我们会遇到<span>xxx</span><textarea ></textarea>,本来我们希望xxx和textarea元素的最高那一行对其,结果发现直接这样写不做设置的话xxx是和textarea元素的最后一行对其,如果textarea高度一定,那么就可以简单通过position:relative来实现预想的效果(修改top属性让<span>元素往上偏移一定像素)
此外,常见的文字浮于图片之上的方式也往往可以通过position:relative实现。只要修改文字或图片其中一者的position:relative对应的top或left属性,然后调整两者的z-index即可。
position:relative相比于position:absulte的好处是它的位置可以随着元素原来所处位置的变化而自动变化(本来relative就是相对元素原来所处位置而言),而position:absulte这种硬编码的方式容易导致后面不断修改的需要。
4.div+css布局记扎
这个部分由于个人觉得实在是比较广泛的,所以另开一贴间歇性更新...不足之处还望见谅
前端的世界里还有很多的见闻,但有些觉得可能比较琐碎,大部分会争取集中到前面提到的div+css布局记扎里更新,其它的可能觉得不是特别重要的发现略去不表,如果有感兴趣探讨的也欢迎留言。
最后谈一下版本管理
本来像我这种一个人开发版本管理看上去不是非常必要,但是因为boss的要求还是专门去学了下svn,但是后来有一次出了一个莫名其妙的bug时才发现版本管理的可贵,直接svn diff命令找出修改的历史,bug瞬间定位。
svn版本管理工具的使用
然后实践过程中发现阿里云的3690(svnserve的端口)端口本地127.0.0.1可以访问但是远程就不行了...后来ping过也是ping不通,不知道是阿里云把它禁了还是怎么的,希望有知道怎么实现远程svn的大虾告知一二!
发现前面写的日志web实践小项目<一>:简单日程管理系统(涉及html/css,javascript,python,sql,日期处理)果然现在再看充满着幼稚(本来之前还打算贴小项目的代码忙完一段时间后现在看来还是不要献丑好了...)
写得应该还是有不少疏漏,欢迎指正讨论!
一个小型线上网站的产生历程