分享

利用同构JavaScript轻松解析URL

 haosunzhe 2015-06-09


大部分web应用都需要解析URL,无论是提取域名、实现REST API,还是查找图片路径。一个典型的URL路径如下图所示:



你可以使用正则表达式把URL字符串拆分为连续的部分,但是这有点复杂而且没必要…


服务端URL解析


Node.js(及其分支,比如io.js)提供了URL API:


// Server-side JavaScript

var urlapi = require('url'),

url = urlapi.parse('http://:81/path/page?a=1&b=2#hash');

console.log(

url.href + 'n' +

// the full URL

url.protocol + 'n' +

// http:

url.hostname + 'n' +

//

url.port + 'n' +

// 81

url.pathname + 'n' +

// /path/page

url.search + 'n' +

// ?a=1&b=2

url.hash

// #hash

);


你可以从上面的片段中看出,parse()方法返回一个包含所需数据(比如协议、主机名、端口等)的对象。


客户端URL解析


浏览器端没有对应的API。但是如果浏览器有件事做得好的话,那就是URL解析和DOM中的链接实现了类似的Location接口,例如:


// Client-side JavaScript

// find the first link in the DOM

var url = document.getElementsByTagName('a')[0];

console.log(

url.href + 'n' +

// the full URL

url.protocol + 'n' +

// http:

url.hostname + 'n' +

//

url.port + 'n' +

// 81

url.pathname + 'n' +

// /path/page

url.search + 'n' +

// ?a=1&b=2

url.hash

// #hash

);


如果我们把URL字符串放到内存的锚点元素(a)中,就可以不依赖正则表达式来解析,例如:


// Client-side JavaScript

// create dummy link

var url = document.createElement('a');

url.href = 'http://:81/path/page?a=1&b=2#hash';

console.log(url.hostname);

//


同构URL解析


Aurelio最近讨论了同构JavaScript应用。实质上,它是将渐进增强(progressive enhancement)推到了极致:应用可以在客户端或服务器上快乐地运行了。使用现代浏览器的用户可以使用单页应用。老式浏览器和搜索引擎爬虫将会看到服务端渲染的应用。理论上,应用可以根据设备的速度和带宽能力来实现不同等级的客户端/服务器处理。


同构JavaScript(Isomorphic JavaScript)已经被讨论过很多年,但是太复杂。很少项目能够在实现共享视图基础之上更进一步,而且标准渐进增强不起作用的情况也不多(如果没有更好地考虑到,大部分没有客户端JavaScript的“同构”框架都会失效)。意思是,可以实现环境无关的宏观库来试探性地迈出同构概念的第一步。


我们考虑下怎样在lib.js文件中编写一个URL解析库。首先,我们检测代码运行的位置:


// running on Node.js?

var isNode = ( typeof module === 'object' && module.exports);


这个方法不是特别健壮,因为你可能在客户端定义了module.exports函数,但是我不知道其他更好的方式(欢迎提供建议)。其他开发者的类似方法是检测window对象是否存在:


// running on Node.js?

var isNode = typeof window === 'undefined';


现在我们使用URLparse函数完成lib.js代码:


// lib.js library functions

// running on Node.js?

var isNode = ( typeof module === 'object' && module.exports);

( function (lib) {

"use strict" ;

// require Node URL API

var url = (isNode ? require('url') : null);

// parse URL

lib.URLparse = function(str) {

if (isNode) {

return url.parse(str);

}

else {

url = document.createElement('a');

url.href = str;

return url;

}

}

})(isNode ? module.exports : this.lib = {});


我在代码中使用isNode变量作澄清。但是,你可以直接把检测代码放到代码片段的最后一个圆括号内。


服务器端,URLparse导出为Common.JS模块。这样使用:


// include lib.js module

var lib = require('./lib.js');

var url = lib.URLparse('http://:81/path/page?a=1&b=2#hash');

console.log(

url.href + 'n' +

// the full URL

url.protocol + 'n' +

// http:

url.hostname + 'n' +

//

url.port + 'n' +

// 81

url.pathname + 'n' +

// /path/page

url.search + 'n' +

// ?a=1&b=2

url.hash

// #hash

);


客户端,URLparse作为全局lib对象的一个方法:


<script src="./lib.js"></script>

<script>

var url = lib.URLparse('http://:81/path/page?a=1&b=2#hash');

console.log(

url.href + '\n' +

// the full URL

url.protocol + '\n' +

// http:

url.hostname + '\n' +

//

url.port + '\n' +

// 81

url.pathname + '\n' +

// /path/page

url.search + '\n' +

// ?a=1&b=2

url.hash

// #hash

);

</script>


除了库中包含的方法,客户端和服务端API都是相同的。


要承认的是,这是一个简单例子,URLparse在不同客户端和服务端上运行(大部分)不同代码。但是我们实现了一致性的API,可以说明JavaScript代码可以运行在任意位置。我们可以扩展这个库来提供更多客户端/服务器实用函数,比如字段验证、cookie解析、日期处理、货币格式等。


考虑到客户端和服务器上不同类型的逻辑,我不确定完全的同构应用是否具有实用性或者可行。但是,环境无关的库可以消除对相同功能编写两份代码的痛苦。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多