安卓版微信Webview中两个页面互相跳转的BUG

前端开发  |  8年前

都说微信是移动端的IE6,不管你们信不信,反正我信了。最近在开发过程中就遇到了一个极其容易触发的BUG。

复现这个BUG只需要两个页面「a.html」以及「b.html」,并且两个页面都有跳去另一个页面的链接:

<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no" />
<title>A</title>
</head>

<body>
<h1>I am A.</h1>
<p><a href="b.html">to B</a></p>
</body>
</html>
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no" />
<title>B</title>
</head>

<body>
<h1>I am B.</h1>
<p><a href="a.html">to A</a></p>
</body>
</html>

先打开「a.html」,点击链接跳转到「b.html」,再点击「b.html」中的链接跳转到「a.html」。如此往复点击跳转几次,就会出现无法再次跳转的情况(会出现进度条,但是无法跳转)。

3475次阅读,5条评论

hashchange事件及其妙用

前端开发  |  9年前

hash即URL中“#”字符后面的部分。使用浏览器访问网页时,如果网页URL中带有hash,页面就会定位到id(或name)与hash值一样的元素的位置,故而又称之为锚点。hash还有另一个特点,它的改变不会导致页面重新加载,因此在单页应用流行的当下,它的用处就更多了。

而hashchange事件,顾名思义,就是hash改变时触发的事件。在 caniuse.com 上查一下兼容性可以发现,IE8就已经支持该事件,但一直以来应用甚少。

hashchange事件兼容性

hashchange事件触发时,事件对象会有hash改变前的URL(oldURL)和hash改变后的URL(newURL)两个属性:

window.addEventListener('hashchange', function(e) {
	console.log(e.oldURL);
	console.log(e.newURL);
}, false);
8650次阅读,0条评论

multer中间件的安全问题

Node.js开发  |  9年前

昨天备份本博客的时候发现,上传目录下多了几个奇怪的.asp和.php文件。这些文件并非我自己上传的,很可能是通过某个漏洞传到了服务器上。这会有什么危害呢?下面简单介绍一下。

假设某人把一个功能为删除站点下所有文件的evil.php通过漏洞传到了http://abc.com/upload/下,然后访问http://abc.com/upload/evil.php,那么:

  • 如果该站点不支持php脚本,是没什么危害的;
  • 如果该站点支持php脚本,它的全部文件就会被删除。

这里有两个关键点,一是主动访问该文件才会触发脚本执行,二是服务器支持该类型脚本才能执行。而本博客刚好不具备这两个条件(后面再详细说明),所以没有造成任何损失。即便如此,这漏洞还是要修复的,不然被无休止地上传文件迟早会占满硬盘空间。

本博客基于express框架开发,上传功能是通过multer中间件实现的,且只有管理后台存在文件上传的功能。因为后台页面、接口都设有权限验证,是不可能被绕过的。最后发现问题出在multer的调用上,而这问题又要归咎于官方文档的错误引导了:

app.use(multer({
	dest: './uploads/',
	rename: function (fieldname, filename) {
		return filename.replace(/\W+/g, '-').toLowerCase() + Date.now()
	}
}))
2150次阅读,2条评论

ECMAScript 6中的面向对象

前端开发  |  9年前

ECMAScript 6(下面简称ES6)增强了对面向对象的支持,引入了class关键字,并且为类的创建、继承提供了简洁清晰的语法。

类声明与类表达式

毋庸置疑,class关键字就是用来定义类的。

定义类的常用方式是类声明,语法如下:

class ClassName {
	// 构造函数
	constructor() {
		// ...
	}

	// 方法
	method() {
		// ...
	}
}
1777次阅读,3条评论

深入理解JavaScript中的面向对象(三)

前端开发  |  9年前

在JavaScript中,虽然借助原型链就可以实现继承,但这里面还是有很多细节问题的要处理的。分析并解决这些问题后,就可以把创建类的过程写成一个通用函数了。

constructor属性

JavaScript中的对象都有一个constructor的属性指向其构造函数。例如:

function A() { }
var a = new A();
a.constructor; // A

确切地说,constructor属性是位于构造函数的prototype上。下面的代码可以证实这一规则:

function A() { }

var a = new A();
console.log(a.constructor); // A

delete A.prototype.constructor; // 删除原型上的constructor属性
console.log(a.constructor); // Object
2190次阅读,1条评论

深入理解JavaScript中的面向对象(二)

前端开发  |  9年前

严格来说,JavaScript并不是一门面向对象的语言,因为它没有原生提供完整的面向对象机制。但它的语言特性又允许我们去模拟大部分这些机制。

new操作符

JavaScript中也用new操作符创建类的实例,例如:

var arr = new Array(10); // 创建长度为10的数组
var date = new Date; // 不需要传参数给构造函数时,括号可以省略

与C#不同的是,JavaScript中new的是函数而不是class,这个函数即为类的构造函数。在构造函数中,可以声明属性和方法。例如:

function Square() {
	this.length = 1;
	this.perimeter = function() {
		return this.length * 4;
	};
}

var square = new Square();
square.perimeter(); // 4
square.length = 10;
square.perimeter(); // 40
2483次阅读,2条评论

深入理解JavaScript中的面向对象(一)

前端开发  |  9年前

在学习JavaScript的过程中,面向对象是必须要学会的课题。然而,网络上大部分文章只是简单地讲述如何通过代码实现面向对象,忽略了理论和原理方面的知识。本系列文章将从头开始逐步讲解面向对象编程思想及其在JavaScript中的实现与应用。

从一个简单的需求开始

假设我们需要在程序中计算各种形状的周长,代码可能是这样的:

var rectangle = {
	name: '长方形1',
	type: 'rectangle',
	length: 5,  // 长
	width: 10   // 宽
};
var square = {
	name: '正方形1',
	type: 'square',
	length: 5  // 边长
};
var circle = {
	name: '圆形1',
	type: 'circle',
	radius: 5  // 半径
};

function computePerimeter(shape) {
	var result;
	switch (shape.type) {
        case 'rectangle':
        	// 矩形周长:(长+宽)*2
        	result = (shape.length + shape.width) * 2;
        	break;
        case 'square':
        	// 正方形周长:边长*4
        	result = shape.length * 4;
        	break;
        case 'circle':
        	// 圆形周长:2*PI*半径
        	result = 2 * Math.PI * shape.radius;
        	break;
    }

    return shape.name + '的周长是' + result;
}
3251次阅读,1条评论

工作经历(五)——56网下篇

工作生活  |  9年前

写好《上篇》并分享到微信朋友圈后,反响热烈。为了感谢大家的支持,我又很快地写好了下篇。下篇主要讲一下技术工作以外的事情。

公司特点

要说56网跟其他IT公司的区别,有以下这些:

  • 很少加班。平时下班后一小时内,公司大部分位置都空了;周末基本上只有客服在。
  • 妹子比例高。产品、运营大部分为妹子,后来测试组也全是妹子,男女搭配,干活不累。
  • 员工回流。虽然人数不多,但确实有几例已离职员工隔了一段时间又重新入职的情况,这在我以前工作过的公司里几乎没有听过。
1984次阅读,7条评论

工作经历(五)——56网上篇

工作生活  |  9年前

在奔步公司萌生了辞职的念头后,我先后去了56网和酷狗面试,前者是通过内部推荐,后者则是猎头介绍。虽然酷狗给的待遇要更高一些,但无论是技术面还是HR面,56网要更加专业,所以我最终选择了56网。

初来乍到

第一天到公司报到,发现这里有不少原网易员工,其中一位设计师还曾经是网易以及3G门户的同事。当然,创始人更是网易创业帮的一员。

上了几天班后,基本上搞清楚了这边Web开发的概况。其中JS出现了职责分裂:前端主要负责UI方面的逻辑,后端PHP会编写一些数据加载、提交方面的逻辑。Web主管和前端主管有意把JS完全纳入前端工作范围,所以需要一个领头的人搭建架构规范代码指导开发,这也就是我的主要任务了。

1851次阅读,3条评论

JavaScript动画实现原理

前端开发  |  9年前

假设有这样一个动画功能需求:把一个div的宽度从100px变化到200px。写出来的代码可能是这样的:

<div id="test1" style="width: 100px; height: 100px; background: blue; color: white;"></div>
function animate1(element, endValue, duration) {
	var startTime = new Date(),
		startValue = parseInt(element.style.width),
		step = 1;
	
	var timerId = setInterval(function() {
		var nextValue = parseInt(element.style.width) + step;
		element.style.width = nextValue + 'px';
		if (nextValue >= endValue) {
			clearInterval(timerId);
			// 显示动画耗时
			element.innerHTML = new Date - startTime;
		}
	}, duration / (endValue - startValue) * step);
}

animate1(document.getElementById('test1'), 200, 1000);

原理是每隔一定时间增加1px,一直到200px为止。然而,动画结束后显示的耗时却不止1s(一般是1.5s左右)。究其原因,是因为setInterval并不能严格保证执行间隔

9692次阅读,1条评论