前端技术演进(二):前端与协议

10次阅读

共计 12036 个字符,预计需要花费 31 分钟才能阅读完成。

这个来自之前做的培训,删减了一些业务相关的,参考了很多资料(参考资料列表),谢谢前辈们,么么哒 ????
目前前后端的通信一般都是通过协议来完成的,这里介绍和前端开发相关的各类协议。
HTTP
HTTP 协议是 Hyper Text Transfer Protocol(超文本传输协议)的缩写,是万维网的数据通信的基础。设计 HTTP 最初的目的是为了提供一种发布和接收 HTML 页面的方法,现在基本上什么类型的文件都可以传输了,比如图片、CSS、JS、数据报文等。
HTTP 一般基于 TCP/IP 通信协议来传递数据,它有如下特点:

简单快速:客户向服务器请求服务时,只需传送请求方法和路径。请求方法常用的有 GET、HEAD、POST。每种方法规定了客户与服务器联系的类型不同。由于 HTTP 协议简单,使得 HTTP 服务器的程序规模小,因而通信速度很快。
灵活:HTTP 允许传输任意类型的数据对象。正在传输的类型由 Content-Type 加以标记。
无连接:无连接的含义是限制每次连接只处理一个请求。服务器处理完客户的请求,并收到客户的应答后,即断开连接。采用这种方式可以节省传输时间。
无状态:HTTP 协议是无状态协议。无状态是指协议对于事务处理没有记忆能力。缺少状态意味着如果后续处理需要前面的信息,则它必须重传,这样可能导致每次连接传送的数据量增大。另一方面,在服务器不需要先前信息时它的应答就较快。
支持 B / S 及 C / S 模式。

HTTP 使用统一资源标识符(Uniform Resource Identifiers, URI)来传输数据和建立连接。URL 是一种特殊类型的 URI,包含了用于查找某个资源的足够的信息。一个完整的 URL 一般包括以下几部分:
协议   域名   端口   虚拟目录   文件名   参数 锚
比如:http://test.google.com:80/test/test.html?query=admin#home
请求消息 Request
通常一个 HTTP 请求消息包含如下内容:请求行、请求头、空行、消息主体。

比如:
GET /books/?sex=man&name=Professional HTTP/1.1
Host: www.example.com
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6)
Gecko/20050225 Firefox/1.0.1
Connection: Keep-Alive

请求行:GET /books/?sex=man&name=Professional HTTP/1.1 用来说明请求类型,要访问的资源以及所使用的 HTTP 版本。比较常见的请求类型有 GET,POST,PUT,DELETE,OPTIONS 等。
请求头:从第二行起为请求头部,用来说明服务器要使用的附加信息。
空行:请求头部后面的空行是必须的,即使请求数据为空,也必须有空行。
请求数据:也叫请求主体,可以添加任意的其他数据,这个例子的请求数据为空。

带有请求数据的 POST 请求:
POST / HTTP/1.1
Host: www.example.com
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6)
Gecko/20050225 Firefox/1.0.1
Content-Type: application/x-www-form-urlencoded
Content-Length: 40
Connection: Keep-Alive

sex=man&name=Professional
响应消息 Response
一般情况下,服务器接收并处理客户端发过来的请求后会返回一个 HTTP 的响应消息。通常一个 HTTP 请求消息包含如下内容:状态行、消息报头、空行、响应正文。
比如:
HTTP/1.1 200 OK
Date: Fri, 22 May 2009 06:07:21 GMT
Content-Type: text/html; charset=UTF-8

<html>
<head></head>
<body>
<!–body goes here–>
</body>
</html>

状态行:由 HTTP 协议版本号,状态码,状态消息 三部分组成。
消息报头:用来说明客户端要使用的一些附加信息。
空行:消息报头后面的空行是必须的。
响应正文,服务器返回给客户端的文本信息。

状态码
状态码由三位数字组成,第一个数字定义了响应的类别,共分五种类别:

1xx:指示信息 – 表示请求已接收,继续处理。
2xx:成功 – 表示请求已被成功接收、理解、接受。
3xx:重定向 – 要完成请求必须进行更进一步的操作。
4xx:客户端错误 – 请求有语法错误或请求无法实现。
5xx:服务器端错误 – 服务器未能实现合法的请求。

常见的状态码有如下几种:

200 OK 客户端请求成功。
301 Moved Permanently 请求永久重定向。
302 Moved Temporarily 请求临时重定向。
304 Not Modified 文件未修改,可以直接使用缓存的文件。
400 Bad Request 由于客户端请求有语法错误,不能被服务器所理解。
401 Unauthorized 请求未经授权。
403 Forbidden 服务器收到请求,但是拒绝提供服务。服务器通常会在响应正文中给出不提供服务的原因。
404 Not Found 请求的资源不存在,例如,输入了错误的 URL。
500 Internal Server Error 服务器发生不可预期的错误,导致无法完成客户端的请求。
503 Service Unavailable 服务器当前不能够处理客户端的请求,在一段时间之后,服务器可能会恢复正常。

HTTP 和 TCP/IP 协议的关系

HTTP/2
HTTP2 即超文本传输协议 2.0 版本,是 HTTP 协议的下一个版本。因为标准委员会不打算再发布子版本了,所以直接叫 HTTP/2,而不叫 HTTP/2.0。
HTTP2 相对于之前的 HTTP 协议有以下几个优点:

HTTP 2 采用完全二进制的格式来传输数据。同时 HTTP 2 对消息头采用 HPACK 压缩传输,最大限度地节省了传输带宽。相比于 HTTP 1.x 每次请求都会携带大量冗余头信息 (例如浏览器 Cookie 信息等),HTTP2 具有很大的优势。
HTTP 2 使用 TCP 多路复用的方式来降低网络请求连接建立和关闭的开销,多个请求可以通过一个 TCP 连接来并发完成。
HTTP2 支持传输流的优先级和流量控制机制。HTTP2 中每个文件传输流都有自己的传输优先级,并可以通过服务器来动态改变,服务器会保证优先级高的文件流先传输。例如在未来的浏览器端渲染中,服务器端就可以优先传输 CSS 文件保证页面的渲染,然后在 CSS 文件全部传输完成后加载 JavaScript 脚本文件。
支持服务器端推送。服务端能够在特定条件下把资源主动推送给客户端。

HTTP 1.1 会让资源排队加载,如下图所示:

但当我们开启了 HTTP/ 2 之后,有了 TCP 多路复用,个数几乎没有限制了,如下图所示:

HTTP/2 将 HTTP 协议通信分解为二进制编码帧的交换,这些帧对应着特定数据流中的消息。所有这些都在一个 TCP 连接内复用。这是 HTTP/2 协议所有其他功能和性能优化的基础。

目前支持 HTTP2 协议传输的浏览器依然很少,随着技术的发展和浏览器的更新迭代,HTTP2 的时代终会到来,但我们依然不能在短时间内企图通过它来帮我们进行页面优化。
HTTPS
HTTPS(超文本传输安全协议 Hypertext Transfer Protocol Secure)经由 HTTP 进行通信,但利用 SSL/TLS 来加密数据包。HTTPS 的主要思想是在不安全的网络上创建一安全信道。通常,HTTP 直接和 TCP 通信。当使用 SSL 时,则演变成先和 SSL 通信,再由 SSL 和 TCP 通信了。简言之,所谓 HTTPS,其实就是身披 SSL 协议这层外壳的 HTTP。HTTP 的 URL 由“http://”起始且默认使用端口 80,HTTPS 的 URL 由“https://”起始且默认使用端口 443。
SSL 是独立于 HTTP 的协议,所以不光是 HTTP 协议,其他运行在应用层的 SMTP 和 Telnet 等协议均可配合 SSL(Secure Socket Layer)协议使用。

HTTP 是不安全的,攻击者通过监听和中间人攻击等手段,可以获取网站帐户和敏感信息等。人们对 HTTPS 有一个普遍的错误认识,认为只有处理敏感通信的网站才需要 HTTPS。每个未受保护的 HTTP 请求都可能暴露与用户行为和身份有关的信息。尽管访问一次未受保护的网站可能看上去无害,但一些入侵者会查看汇总的用户浏览活动,以推断他们的行为和意图,从而进行去匿名化攻击,查出匿名用户的身份。例如,员工可能在阅读未受保护的医疗文章时不经意地向其雇主泄露敏感的健康信息。
公钥和私钥
加密和解密同用一个密钥的方式称为共享密钥加密(Common key crypto system),也被叫做对称密钥加密。

以共享密钥方式加密时必须将密钥也发给对方。可究竟怎样才能安全地转交?在互联网上转发密钥时,如果通信被监听那么密钥就可会落入攻击者之手,同时也就失去了加密的意义。
SSL 采用一种叫做公开密钥加密(Public-key cryptography)的加密处理方式。公开密钥加密使用一对非对称的密钥。一把叫做私有密钥(private key),另一把叫做公开密钥(public key)。顾名思义,私有密钥不能让其他任何人知道,而公开密钥则可以随意发布,任何人都可以获得。
使用公开密钥加密方式,发送密文的一方使用对方的公开密钥进行加密处理,对方收到被加密的信息后,再使用自己的私有密钥进行解密。利用这种方式,不需要发送用来解密的私有密钥,也不必担心密钥被攻击者窃听而盗走。

HTTPS 采用混合加密机制:

证书颁发机构
公开密钥加密方式还是存在一些问题的。那就是无法证明公开密钥本身就是货真价实的公开密钥。
证书颁发机构 (CA) 是一个组织,对公钥和与公共 DNS 名称之间的映射进行证实。例如,客户端如何知道特定公钥是否为 www.foobar.com 的真实公钥?按理说,无法知道。CA 证实特定密钥是特定网站的真实密钥,它使用自己的私钥来加密签名该网站的公钥。此签名在计算上是无法伪造的。浏览器(和其他客户端)维护信任锚存储库,它包含知名 CA 拥有的公钥,并且它们使用这些公钥来加密验证 CA 的签名。
SSL 握手流程

最后使用共享密钥来进行以后的通信,详细流程:

Websocket
在实际的前端应用项目中,除了使用应答模式的 HTTP 协议进行普通网络资源文件的请求加载外,有时也需要建立客户端与服务端之间的实时连接进行通信,例如网页实时聊天的应用场景,这就必须涉及浏览器端的实时通信协议了。对于这些对实时性要求较高的应用场景,普通的 HTTP 协议就并不适用。虽然前端可以通过 Ajax 定时向服务端轮询的方式来持续获取服务端的消息,但是这种方式效率相对较低。
WebSocket 是浏览器端和服务器端建立实时连接的一种通信协议,可以在服务器和浏览器端建立类似 Socket 方式的消息通信。相对于 HTTP1.1 协议,WebSocket 协议的优势是方便服务器和浏览器之间的双向数据实时通信。
7 层网络模型
这里只是类似 Socket 方式,WebSocket 是建立在 TCP/IP 协议之上,属于应用层的协议,而 Socket 是在应用层和传输层中的一个抽象层,它是将 TCP/IP 层的复杂操作抽象成几个简单的接口来提供给应用层调用。简单回顾一下 7 层网络模型:

简单来说,我们在传输数据时,可以只使用 (传输层)TCP/IP 协议,但是那样的话,如果没有应用层,便无法识别数据内容。如果想要使传输的数据有意义,则必须使用到应用层协议。应用层协议有很多,比如 HTTP、FTP、TELNET 等,也可以自己定义应用层协议。WEB 使用 HTTP 协议作应用层协议,以封装 HTTP 文本信息,然后使用 TCP/IP 做传输层协议将它发到网络上。
TCP/IP 只是一个协议栈,就像操作系统的运行机制一样,必须要具体实现,同时还要提供对外的操作接口。这个就像操作系统会提供标准的编程接口,比如 win32 编程接口一样,TCP/IP 也要提供可供程序员做网络开发所用的接口,这就是 Socket 编程接口。Socket 的出现只是使得程序员更方便地使用 TCP/IP 协议栈而已,是对 TCP/IP 协议的抽象,从而形成了我们知道的一些最基本的函数接口,比如 create、listen、connect、accept、send、read 和 write 等等。

Websocket 使用
WebSocket 的实现分为握手,数据发送 / 读取,关闭连接。

var ws = new WebSocket(“wss://echo.websocket.org”);

ws.onopen = function(evt) {
console.log(“Connection open …”);
ws.send(“Hello WebSockets!”);
};

ws.onmessage = function(evt) {
console.log(“Received Message: ” + evt.data);
ws.close();
};

ws.onclose = function(evt) {
console.log(“Connection closed.”);
};
在线演示:https://html5demos.com/web-socket/
DDP
DDP (Distributed Data Protocol,分布式数据协议)是一种新型的客户端与服务器端的实时通信协议,由于兼容性的原因,目前使用还不广泛。
DDP 使用 JSON 的数据格式在客户端和浏览器之间进行数据传输通信,所以对于前端开发者来说使用非常方便。有名的 Meteor Web 框架的双向实时数据更新机制底层使用的就是 DDP,这种协议模式下客户端可向服务器端发起远程过程调用,客户端也可以订阅服务端数据,在服务端数据变化时,服务器会向客户端发起通知,触发浏览器响应的操作。
// 创建服务端
const DDPClient = require(‘ddp’);
const client = new DDPClient({
host: ‘localhost’,
port: 3000
});

// 监听消息
client.on(‘message’, function(data, flags){
console.log(‘[DDP 消息]: ‘, data);
});

// 创建连接
client.connect(function(){
client.subscribe(‘post’,[],function(){
console.log(‘[post 订阅消息]’);
});
});
协议标准:https://github.com/meteor/meteor/blob/devel/packages/ddp/DDP.md
RESTful
REST (Representational State Transfer,表述性状态转化)并不是某一种具体的协议,而是定义了一种网络应用软件之间的架构关系并提出了一套与之对应的网络之间交互调用的规则。与之类似的例如早期的 WebSevice,WebSevice 现在基本都不用了。
在 REST 形式的软件应用服务中,每个资源都有一个与之对应的 URI 地址,资源本身都是方法调用的目标,方法列表对所有资源都是一样的,而且这些方法都推荐使用 HTTP 协议的标准方法,例如 GET、POST、PUT、DELETE 等。如果一个网络应用软件的设计是按照 REST 定义的,我们就可以认为它使用的交互调用的方法设计遵循 RESTful 规范。换种方式理解,RESTful 是一种软件架构之间交互调用数据的协议风格规范,它建议以一种通用的方式来定义和管理数据交互调用接口。
例如:对于书籍 book 的记录管理接口,有增、刪、改、查操作,于是我们定义接口:

path/addBook
path/deleteBook
path/updateBook
path/getBook

看上去好像没有什么问题。后来,另一个项目也有类似的接口定义,却可能叫作:

path/appendBook
path/delBook
path/modifyBook
path/getBook

接着有一天,项目负责人可能会说,要升级接口来满足新的需求,于是我们又添加了:

path/addBook2
path/deleteBook2
path/updateBook2
path/getBook2

这样用起来是没有什么问题,但是这些随意的定义会增加数据接口维护难度和项目继续开发的成本。
这时,我们或许会考虑使用文档或规范,规定一定要使用 add 来添加,新的接口版本号放前面 path/v2/addBook,开发的人必须严格按照文档规范去写。这样做很好,但依然不够完善,原因有以下几点:

因为项目工作常常排期紧张,你可能没时间去写文档,或者后面接手的人不想去看文档。
开发修改功能后很可能来不及或忘记去更新文档。
无论文档写得多清楚,我们看起来效率总是很低。

这时如果有一个风格更好的通用规范来定义数据交互接口,就不用这么麻烦了。所以我们完全可以利用 RESTful 设计的规范特性来解决上面遇到的问题。对于书籍记录操作接口的命名可以如下操作:

HTTP 方法
URI
描述

POST
path/v1/book
新增书籍信息

DELETE
path/v1/book
删除书籍信息

PUT
path/v1/book
更新书籍信息

GET
path/v1/book
获取书籍信息

使用 RESTful 规范来重新设计接口后,一切就变得很清晰自然,这样新的工程师接手项目时,只要他足够了解 RESTful 规范,几乎没有时间成本。即使他不了解 RESTful 规范,也可以很快地去了解,这就可以避免他去读那份看似完善其实冗长杂的文档。
这里涉及到了几个设计的原则:

“资源”表示一种实体,所以应该是名词,URL 不应该有动词,动词应该放在 HTTP 协议中。
按照标准,不应该在 URL 中包含版本号,应该放在 HTTP 请求头信息的 Accept 字段中,不过这样不够直观,所以一般的方式还是把版本号放在 URL 中,算是一个反模式。

RESTful API 的主要设计原则就是这些,总结来说就是结合 HTTP 的固有方式来表征资源的状态变化描述,而不是通过动词加名词的方式来设计。
Github RESTful API:https://developer.github.com/v3/
GraphQL
GraphQL 对 API 中的数据提供了一套易于理解的完整描述,使得客户端能够准确地获得它需要的数据,而且没有任何冗余,也让 API 更容易地随着时间推移而演进。
GraphQL 解决的最重要的 3 个问题分别是:

需要进行多次往返以获取所需的数据:典型的 REST API 请求多个资源时得载入多个 URL,而 GraphQL 可以通过一次请求就获取你应用所需的所有数据。

客户端依赖于服务端:消除了服务器对数据内容进行硬编码的需要。我们可以把客户端与服务端分离开来,单独进行维护和改进。前后端彻底分离。

糟糕的前端开发体验:使用 GraphQL,开发人员可以声明式地来表达其用户界面的数据需求,不用总是关注数据是如何获取的。

RESTful APIs vs GraphQL APIs
一个简单的示例:我们要做一个星球大战人物信息展示的 UI 界面:需要显示人物的姓名,出生年份,星球名称以及所有他们参演的电影的名称。
这个 UI 的 JSON 数据可能类似于:
{
“data”: {
“person”: {
“name”: “Darth Vader”,
“birthYear”: “41.9BBY”,
“planet”: {
“name”: “Tatooine”
},
“films”: [
{“title”: “A New Hope”},
{“title”: “The Empire Strikes Back”},
{“title”: “Return of the Jedi”},
{“title”: “Revenge of the Sith”}
]
}
}
}
如果使用 React.js,一般会这样表示视图:
// The Container Component:
<PersonProfile person={data.person} ></PersonProfile>

// The PersonProfile Component:
Name: {person.name}
Birth Year: {person.birthYear}
Planet: {person.planet.name}
Films: {person.films.map(film => film.title)}
如果使用 RESTful API,我们可能这样请求数据:
1、获取人物信息:
GET – /people/{id}
{
“name”: “Darth Vader”,
“birthYear”: “41.9BBY”,
“planetId”: 1
“filmIds”: [1, 2, 3, 6],

}
2、获取星球信息:
GET – /planets/1
3、获取所有电影信息:
GET – /films/1
GET – /films/2
GET – /films/3
GET – /films/6
演示
我们需要发送 6 个请求才能获取到所有需要的数据,每个获取数据的方法都是命令式的。每个接口返回的信息还有很多字段不是我们所需要的。为了解决这个问题,我们可能会新增加一个接口,比如:
GET – /people/{id}/films
但是这样就不是纯粹的 RESTful API 了,而且后端要额外的创建这个接口,用来满足前端的数据要求,如果增减字段或对象,后端还要添加接口或者重新编码。
如果使用 GraphQL,我们可以这样来查询:
GET or POST – /graphql?query={…}
比如参数使用:
{
person(personID: 4) {
name,
birthYear,
homeworld {
name
},
filmConnection {
films {
title
}
}
}
}
演示
一个请求就完成了所有数据的获取。
GraphQL 的灵活性也会带来一些问题,比如增加复杂度,资源耗尽攻击,N+ 1 查询等。FB 针对 N + 1 给出了 dataloader 的方案。
Github GraphQL API:https://developer.github.com/v4/
在线调试:https://developer.github.com/v4/explorer/
与 Native 交互
Hybrid App 是在 Native App 应用的基础上结合了 Web App 应用所形成的模式,一般称之为混合 App。从技术开发上来看,相比于传统的桌面浏览器端的 Web App,它具有以下几方面的特征:

可用的系统网络资源更少。由于移动设备 CPU、内存、网卡、网络连接多方面的限制,HybridApp 的前端页面可用的系统资源远远小于桌面浏览器。就网络连接来说,大部分移动设备的使用者使用的仍是 3G、4G 的网络,带宽和流量均有限制,和桌面浏览器的带宽接入相比还是有着本质上的区别。

支持更新的浏览器特性。目前智能设备浏览器种类相对较少,且随着硬件设备的快速更新,主流的浏览器以 WebKit 内核居多,支持较新的浏览器特性。不像桌面浏览器那样需要考虑较低版本 Internet Explorer 的兼容性问题。

可实现离线应用。Hybrid 的一个优势是可以通过新的浏览器特性或 Native 的文件读取机制进行文件级的文件缓存和离线更新。这是桌面浏览器, 上较难做到的。这些离线机制常常可以用来弥补 Hybrid App 网络系统资源不足的缺点,让浏览器脚本更快从本地缓存中加载。

较多的机型考虑。由于目前移动设备平台不统一,而且不同设备机型系统的浏览器实现仍有一定的区别,因此 Hybrid App 应用需要考虑不同设备机型的兼容性问题。

支持与 Native 交互。Hybrid App 的另一个特点是结合了移动端 Native 特性,可以在前端页面中调用客户端 Native 的能力,例如摄像头、定位、传感器、本地文件访问等。

Web 调用 Native
在 HTML5 中调用 Native 程序一般有几种较通用的方法:
一、通过 URI 请求。
Native 应用可在移动端系统中注册一个 Scheme 协议的 URI,这个 URI 可在系统的任意地方授权访问来调起一段原生方法或一个原生的界面。同样,Native 的 WebView 控件中的 JavaScript 脚本的请求也可以匹配调用这一通用的 Scheme 协议。例如我们通过对 window.location.href 赋值或使用 iframe 的方式发送一个 URI 的请求,这个请求可以被 Native 应用的系统捕获并调起 Native 应用注册匹配的这个 Scheme 协议内容。
比如微信的 scheme 为(weixin://)。

二、通过 addJavascriptInterface(Android)或 JavaScriptCore(iOS)注入方法到页面中调用。
Android,原生 Webview 需要先注册可供前端调用的 JS 函数:
// Android 容器允许 JS 脚本,必须要
webSettings.setJavaScriptEnabled(true);
// Android 容器设置侨连对象
mWebView.addJavascriptInterface(getJSBridge(), “JSBridge”);

// Android4.2 版本及以上,本地方法要加上注解 @JavascriptInterface,否则会找不到方法。
private Object getJSBridge(){
Object insertObj = new Object(){
@JavascriptInterface
public String foo(){
return “foo”;
}

@JavascriptInterface
public String foo2(final String param){
return “foo2:” + param;
}

};
return insertObj;
}
然后 H5 中即可调用原生中注册的函数:
// 调用方法一
window.JSBridge.foo(); // 返回:’foo’
// 调用方法二
window.JSBridge.foo2(‘test’); // 返回:’foo2:test’
iOS,需要引入 JavaScriptCore 库:
#import <JavaScriptCore/JavaScriptCore.h>
然后原生需要注册 API:
//webview 加载完毕后设置一些 js 接口
-(void)webViewDidFinishLoad:(UIWebView *)webView{
[self hideProgress];
[self setJSInterface];
}

-(void)setJSInterface{

JSContext *context =[_wv valueForKeyPath:@”documentView.webView.mainFrame.javaScriptContext”];

// 注册名为 foo 的 api 方法
context[@”foo”] = ^() {

// 获取参数
NSArray *args = [JSContext currentArguments];
NSString *title = [NSString stringWithFormat:@”%@”,[args objectAtIndex:0]];
// 做一些自己的逻辑
// 返回一个值 ‘foo:’+title
return [NSString stringWithFormat:@”foo:%@”, title];
};

}
之后前端就可以调用了:
// 调用方法, 用 top 是确保调用到最顶级, 因为 iframe 要用 top 才能拿到顶级
window.top.foo(‘test’); // 返回:’foo:test’
三、改写浏览器原有对象。
通过修改原来浏览器的 window 某些方法,然后拦截固定规则的参数,然后分发给 Java 对应的方法去处理。这里常用的是以下四个方法:

alert,可以被 webview 的 onJsAlert 监听
confirm,可以被 webview 的 onJsConfirm 监听
onsole.log,可以被 webview 的 onConsoleMessage 监听
prompt,可以被 webview 的 onJsPrompt 监听

Native 调用 Web
需要先使用 JavaScript 在 HTML5 页面全局中声明相对应的方法。
然后 Native 向 HTML5 发起调用,Android 平台一般通过 loadUrl,iOS 通常通过 stringByEvaluatingJavaScriptFromString 实现。
Android 调 HTML5:
// 异步执行 JS 代码, 并获取返回值
mWebView.evaluateJavascript(“javascript: 方法名 (‘ 参数, 需要转为字符串 ’)”, new ValueCallback<String>() {
@Override
public void onReceiveValue(String value) {
// 这里的 value 即为对应 JS 方法的返回值
}
});
iOS 调 HTML5:
// 可以取得 JS 函数执行的返回值
// 方法必须是 Html 页面绑定在最顶层的 window 上对象的
// 如 window.top.foo
[webView stringByEvaluatingJavaScriptFromString:@” 方法名 ( 参数);”];
JSBridge

JSBridge 是 HTML5 与 Native 通信的桥梁,其作用是实现 HTML5 与 Native 间的双向通信。JSBridge 综合了上面的技术,更多的是一种形式、一种思想,各家的实现方式也略有差异。比如微信 JSSDK,就是基于 WeixinJSBridge,微信浏览器中的页面,通过 WeixinJSBridge 调用微信提供的一些原生功能。

正文完
 0