分类目录归档:Web

记一次因错误的500页面引发的血案

讲故事,就得先介绍一下背景:

业务上线了某活动页面,但是点击至某固定链接时,页面跳转至首页。

排查过程如下:

  1. 确定是否稳定复现,结果:其他未跳转至首页的用户无此现象。而一旦跳转至首页的用户,则访问相关链接永远跳首页。
  2. http抓包,发现无此链接的请求,而是直接请求到了首页
  3. 怀疑系统缓存,发现缓存内容为:<meta http-equiv=”refresh” content=”0;url=/”>

Meta 背景知识:

http://www.metatags.info/meta_http_equiv_refresh

最终定位:

由于跳转的操作在开发环境永远无法复现,怀疑与生产环境有关。最终对比nginx配置如下:

而生产环境存在50x.html,其内容:

在系统上线时,会进行文件替换及产生新的autoload文件。此时的访问可能会由于文件内容不完全等原因,会产生500错误。so~

结论:

系统可以在500错误时给出相关提示引导。但是上述直接跳转至首页会导致缓存,因此一旦跳转一次后续再访问会直接读取缓存再次跳转。

解决方法:

  1. 在50x.html页面,增加禁止缓存操作,参考:http://www.metatags.info/meta_http_equiv_cache_control
  2. 给一个更友好的500错误提示页面,参考:

理解goroutine

在示例中runtime.Gosched前后各加一条输出果然看得就比较清楚了:

1、启goroutine

2、主线程继续执行say(“hello”)

3、主线程输出 ~~hello

4、主线程遇到runtime.Goshed,切换CPU去执行goroutine——say(“world”)

5、输出 ~~world

6、goroutine遇到runtime.Goshed,切换CPU去执行主线程

7、主线程继续向下执行输出 hello,及2~~hello

8、主线程第一次for循环结束,将i++,并输出 ~~hello

9、主线程遇到runtime.Goshed,切换CPU去执行goroutine

10、输出 world及2~~world,第一次for循环结束,输出~~world

11、goroutine再次遇到runtime.Goshed,切换CPU去执行主线程

12、主线程输出hello及2~~hello,将i++已经>2,主线程结束循环退出

最终输出内容为:

~~ hello
~~ world
hello
2~~ hello
~~ hello
world
2~~ world
~~ world
hello
2~~ hello

DNS解析过程及DNS TTL值

经常说DNS劫持,也常常说域名解析不正确。那么DNS解析的过程究竟如何?在阅读《HTTP权威指南》缓存一章时,提到缓存文档过期采用“生存时间技术”与DNS类似。所以抽空学习了解了一下DNS的解析过程,以及DNS TTL值的概念!

DNS相关知识

  • 根域名服务器(root-servers.org)是互联网域名解析系统(DNS)中最高级别的域名服务器,全球仅有13台根服务器。
  • 部分根域名服务器在全球设有多个镜像服务器
  • 任何域名解析都要经过这13台根服务器获得顶级索引,并不是说您访问 .com 会经过这些服务器,访问 .cn 就不经过这些服务器
  • 每一个顶级域,不管是gTLD(通用顶级域),还是ccTLD(国别顶级域),它们都有自己的域名服务器(即该顶级域的NS记录)

根域名服务器全球分布图——Google Maps

域名解析的步骤

继续阅读

网络运营商是否属于拦截代理

在阅读“代理”相应内容时,心里一直有一个疑惑。网络运营商是否属于代理的一种——拦截代理。

运营商们于网络请求的中间,负责着连接用户到广域互联网,起着桥的作用。一般运营商会为网络宽带设置提供DNS服务器,也会为减少带宽来进行通用数据的缓存。那么在某些时刻是否与代理的作用相同?
继续阅读

思考题:如下场景如何设计mongo collection

Mongo 中collection相当于MySQL的表,那么当我有下面需求时,我应该如何设计我的collection及字段(key/value结构)?

场景及需求描述:

  1. 记录用户每次登录的业务标识及ip,以及登录时间
  2. 指定qid、ip需要查询该ip是否已经存在

针对上述需求,我的collection应该如何设计?

目前有两种方案,正在纠结于哪个更好一些:

  • 方案一
  • 方案二

第一种方案,清晰,多对多的关系。足够的明朗!相对查询条件应该足够的简单:findOne({userid:$userid,appid:$appid,ip:$ip});

第二种方案,一对多的关系,查询起来指定条件比较麻烦!findOne({userid:$userid,appid:$appid,ipArr.ip:$ip});

注明:上述说的查询语句可能不准确(刚接触Mongo)

那么到底应该选择哪种?又如何来创建合适的索引?

别急,现在增加一个新的需求:每个用户,同一业务,只记录最新的5条记录!

好吧,我现在还不确定方案如何选择,以及最后一个需求具体该如何实现。明天和同事们讨论,更新本日志Mark一下!
PS:是不是使用PHP来做条数限制会更好一些?

最终决定采用第二种方案,实现上通过PHP的client端获取用户ip数组,使用PHP来操作数组元素的增加及删除,最后再upsert至Mongo中。

使用php的查询条件可以如下(取决于你想取什么,实际实现上userid及appid即可限制条件了)