火车时刻表WebApp
关键词 :Ajax 跨域访问 php 同源策略 JQueryMobile
前言
在面试的过程中,兄弟连的徐老师提出要求我用JQuery Mobile(前端框架)来实现一个具有“火车时刻表”功能的WebAPP。
在做的过程中,我遇到了
- Ajax——更底层地说是JavaScript——的跨域问题;
- JQuery Mobile前端框架使用的问题。
开发环境/工具
| 名称 | 下载地址 |
| JQuery Mobile 类库 | |
| AJAXCDR 类库 | http://blog.zyan.cc/demo/ajaxcdr/ajaxcdr-1.0.zip |
| Apache2.2 | |
| PHP5.4 | |
| Dreamweaver CS6 | |
| 火车时刻api——“聚合数据” | http://www.juhe.cn/docs/api/id/79 |
关键技术及原理分析
由于是该项目的目标是webApp,所以加载火车时刻数据的操作就必须交给前台来实现——JavaScript。在实际操作中我发现,当我使用JQuery从API加载数据时,脚本意外中止,使用Chrome浏览器的调试功能,在控制台那一栏发现报错。如下图。

错误信息:
GET http://localhost/favicon.ico 404 (Not Found)
XMLHttpRequest cannot load http://op.juhe.cn/onebox/train/query_ab.php?key=c18fca22564a4af761bdd7ed52707fb2&from=123&to=321. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost' is therefore not allowed access.
错误原因:JavaScript不能跨域访问。
关于“跨域访问”在这篇博文里讲的非常清楚了。
技术可行性分析——Ajax跨域访问的解决方案
方案一 JSONP
JSONP是JSON with Padding的略称。它是一个非官方的协议,它允许在服务器端集成Script tags返回至客户端,通过javascript callback的形式实现跨域访问(这仅仅是JSONP简单的实现形式)。
但缺点是不能实现POST请求。
由于数据源是第三方api,我无法更改第三方的后台程序接口。所以,该方案不可行。
方案二 iframe
具体实现可以参考这个博文:《利用iframe实现ajax 跨域通信的解决方案》。
但是相比较JSONP的方法,这个方法比较麻烦,而且还是要修改服务端。
方案三 CORS
关于CORS的方法实现,也是需要修改服务端(晕,基本都要修改服务端)。但是相比较于JSONP,CORS能实现GET和POST请求;相比于iframe,CORS的前端更简单。具体CORS方法的实现,可以参考这篇博文:《CORS——AJAX POST&跨域 解决方案》
方案四 访问同源代理(本项目)
开门见山,该方案的操作方法是在本地写一个代理。
既然“同源策略”规定了Ajax不能访问同以外的域,那么就在本域内写一个代理(proxy)来实现数据的“路由”。前端不做过多修改,就像访问原生API一样。
本文将着重介绍同源代理的实现方案。
方案五 axajcdr跨域访问
AJAXCDR是由张宴实现的一种ajax + flash跨域访问方案。详见这篇博文:AJAXCDR:利用 Flash 完美解决 JavaScript 和 AJAX 跨域 HTTP POST/GET 表单请求
但是在本项目里面不适用,因为该方案需要在服务端根目录下有一个crossdomain.xml文件。还是那个原因,我不能修改服务端。
详细设计
一,代理(proxy)设计
好的代理应该具有非常强的透明性——代理对于上一层的程序员应该是“不存在”的。换句话说,对于前端程序员从代理收发数据和直接访问API是一样的。即使有区别,那也应该是非常微小的区别。这样在将来项目运行环境有变化时,程序员不必用太多时间修改。
proxy.php 代码如下:
<?php
/*
*file name : proxy.php
*$_SERVER['REQUEST_URI'] =
* 'RailwayTimetable_beta/proxy.php?request=http://op.juhe.cn/onebox/train/query_ab.php?key=c18fca22564a4af761bdd7ed52707fb2&from=%E6%8A%9A%E9%A1%BA&to=%E6%B2%88%E9%98%B3';
*/
$requestArr = explode('request=', $_SERVER['REQUEST_URI']);
echo file_get_contents($requestArr[1]);
二,前端设计
前端主要使用了JQuery Mobile类库,访问远程API使用了Ajax。
关于“Ajax拒绝跨域问题”解决方法是修改URL,在“聚合数据API”URL前加上代理的地址,并且把API的url视为参数进行传输。可以参考的例子详见百度搜索引擎的跳转,如下URL:
本项目前台URL访问的实现如下URL:
/RailwayTimetable_beta/proxy.php?request=http://op.juhe.cn/onebox/train/query_ab.php?key=c18fca22564a4af761bdd7ed52707fb2&from=%E6%8A%9A%E9%A1%BA&to=%E6%B2%88%E9%98%B3
index.html文件的代码如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>列车时刻表查询</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="css/jquery.mobile-1.4.3.css"/>
</head> <body> <div data-role="page" id="index"> <div data-role="header" data-position="fixed">
<h1>列车时刻表查询</h1>
</div> <div role="main" class="ui-content">
<div class="ui-field-contain">
<label>发车站:</label>
<input type="text" name="text-basic" id="search-begin" value="">
</div>
<div class="ui-field-contain">
<label>终点站:</label>
<input type="text" name="text-basic" id="search-end" value="">
</div> <input type="button" value="搜索" id="search-submit"> <div class="ui-grid-c" id="timeTable2">
<div class="ui-block-a">车次</div>
<div class="ui-block-b">发车时间</div>
<div class="ui-block-c">到站时间</div>
</div>
</div> <div data-role="footer">
<div data-role="navbar">
<ul>
<li><a href="#" data-icon="grid" class="ui-btn-active">查询</a></li>
<li><a href="#" data-icon="star">收藏</a></li>
<li><a href="#" data-icon="gear">设置</a></li>
</ul>
</div>
</div>
</div> <script src="js/jquery-1.11.1.js"></script>
<script src="js/jquery.mobile-1.4.3.js"></script>
<script>
//初始化
var isBind = 0;
var AppKey = "c18fca22564a4af761bdd7ed52707fb2";
var resource = "./proxy.php";
var resourceS2S = "http://op.juhe.cn/onebox/train/query_ab.php";
var resourceTrainNumber = "http://op.juhe.cn/onebox/train/query"; //获取列车车次
function getQueryURL(){
var url = null;
if (!$("#search-no").val()) {
//按照站对站方式查找
url = resourceS2S
+ "?key="
+ AppKey
+ "&from="
+ encodeURIComponent($("#search-begin").val())
+ "&to="
+ encodeURIComponent($("#search-end").val());
} else {
//按照车次方式查找
url = resourceTrainNumber
+ "?key="
+ AppKey
+ "&train="
+ encodeURIComponent($("#search-no").val());
}
return resource + '?request=' + url;
} //获取车次列表
function getTrainList(){
//数据校验
if ($("#search-no").val() || ($("#search-begin").val() && $("#search-end").val())) { //按钮失效效果
var searchButton = $(this);
searchButton.button("option", "disabled", true); //显示加载中
$.mobile.loading('show'); //Ajax 通信
var url = getQueryURL();
//$("#list").html(url);
$.getJSON(url, function(data){
render(data);
//alert(data);
}); //关闭加载中
$.mobile.loading("hide");
//按钮失效恢复
searchButton.button("option", "disabled", false); }else{
alert("请输入发车站和终点站或输入车次!");
}
} //解析JSON,并显示
function render(data){
//$("#list").append("<li>" + data.result.list.train_no + "</li>");
if(data.reason != "查询成功"){
alert(data.reason);
$("#timeTable2").html("");
}
$.each(data.result.list, function(i,item){
addRow(item.train_no, item.start_time, item.end_time);
//addRow(item.train_type);
});
} function addRow(rowA, rowB, rowC){
var row =
"<div class=\"ui-block-a\">"+ rowA +"</div>" +
"<div class=\"ui-block-b\">"+ rowB +"</div>" +
"<div class=\"ui-block-c\">"+ rowC +"</div>" ; $("#timeTable2").append(row);
} //绑定事件
var bindEvent = function () {
$("#search-submit").on("click", getTrainList);
}; $(document).on("pageshow", "#index", function () {
if (isBind) return
isBind = 1;
bindEvent();
}); </script>
</body>
</html>
使用方法及运行效果
使用方法:输入“发车地”名称,输入“终点站”名称,比如:抚顺,沈阳。详见下图:

点击查询按钮,结果如下图:

就酱紫,完毕!
源码下载
http://yunpan.cn/ccdGPTJDR9mtE 访问密码 5c58
参考资料
http://www.cnblogs.com/yjmyzz/archive/2011/04/26/2029699.html
http://www.cnblogs.com/chopper/archive/2012/03/24/2403945.html
http://www.cnblogs.com/wangfupeng1988/p/4060747.html
火车时刻表WebApp的更多相关文章
- 常用Web Service汇总(天气预报、时刻表等)
现成的Web Service中有很多很好用的,比如天气预报,IP地址搜索,火车时刻表等等.本文汇总的一些常用Web Service,希望对大家有所帮助. AD: ================= ...
- [转载]常用Web Service汇总(天气预报、时刻表等)
下面总结了一些常用的Web Service,是平时乱逛时收集的,希望对大家有用. ============================================ 天气预报Web Servic ...
- 我的Android进阶之旅------>关于调用Webservice查询火车票时刻表的几个接口介绍
今天发现一个可以提供火车票时刻表查询的WebService,先记录下来以后如果写一个火车票时刻表查询的Android App的话就用的着.首先该WebService的的名字是TrainTimeWebS ...
- java抓取12306火车余票信息
最近在弄一个微信的公众帐号,涉及到火车票查询,之前用的网上找到的一个接口,但只能查到火车时刻表,12306又没有提供专门的查票的接口.今天突然想起自己直接去12306上查询,抓取查询返回的数据包,这样 ...
- 《C#开发常用免费WebServices集合》
天气预报 Web服务,数据来源于中国气象局 公用事业 http://www.webxml.com.cn/WebServices/WeatherWebService.asmx 中国股票行情 分时走势预览 ...
- 最实用的IT类网站及工具大集合
1.聚合数据 大家在开发过程中,可能会用到各种各样的数据,想找一些接口来提供一些数据.比如天气预报查询,火车时刻表查询,彩票查询,身份证查询等等.有了这个接口,直接调用即可.各种各样的API接口满足你 ...
- 干货!IT小伙伴们实用的网站及工具大集合!持续更新!
1.Git 还在担心自己辛辛苦苦写的代码被误删了吗?还在担心自己改错了代码不能挽回吗?还在苦恼于多人开发合作找不到一个好的工具吗?那么用Git就对 了,Git是一个开源的分布式版本控制系统,用以有效. ...
- jQuery Mobile应用之火车票查询
效果图: 在CMD中输入如下代码 corsproxy (前提是有node.js环境,并先安装corsproxy) html: <!DOCTYPE html> <html> &l ...
- 常用的WEB服务
1.股票行情数据 Web Service(支持香港.深圳.上海基金.债券和股票:支持多股票同时查询) http://www.webxml.com.cn/WebServices/StockInfoWS ...
随机推荐
- SQL数据库存储过程
添加修改 create PROCEDURE sp_insert_1(pid int,pname varchar(200),page varchar(200),pscore int,out code i ...
- 如何快速知道一个颜色的rgb值
1.如果你想使用某种颜色缺不知道rgb值是多少,可以将一张图片用系统自带的画图(我的系统是win7)0工具打开,点击编辑颜色就会出现调色板,然后就可以选择查看具体颜色的rgb值了 2.如果你想知道某个 ...
- iOS 开发笔记-加载/初始化
ViewDidLoad 一般我们会在这里做界面上的初始化操作,比如往view中添加一些子视图.从数据库或者网络加载模型数据装配到子视图中 在自定义控制里 initWithFrame:一般用于添加控件, ...
- 10.用js下载文件(需要后端链接)
用js下载文件 PS:本文说的,并非如何用js创建流.创建文件.实现下载功能. 而是说的:你已知一个下载文件的后端接口,前端如何请求该接口,实现点击按钮.下载文件到本地.(可以是zip啦. ...
- php 门面模式
1.门面模式为外部提供一个统一的接口,外部调用者不用知道内部的具体复杂业务. 2.如果不使用门面模式,直接访问内部系统,会造成相互直接的耦合关系, 3.想让你的子系统开通哪些,就开通哪些,在门面上开通 ...
- Nodejs【单机】多进程模式集群
Nodejs[单机]多进程模式集群实例: 1.安装:npm install -s cluster 2.服务代码: var debug = require('debug'); var express = ...
- spark-shell下有提示了,但是发现不能退格
配好了Spark集群后,先用pyspark写了两个小例子,但是发现Tab键没有提示,于是打算转到scala上试试,在spark-shell下有提示了,但是发现不能退格,而且提示也不是复写,而是追加,这 ...
- django 定义文章url
url(r'^firstcontent/'+str(date)+'/(?P<first_body_id>\d+)/$', views.firstcontent, name='firstco ...
- Vue系列之 => 使用钩子函数的第二个参数传参
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- 【Linux学习三】VI/VIM全屏文本编辑器
环境 虚拟机:VMware 10 Linux版本:CentOS-6.5-x86_64 客户端:Xshell4 FTP:Xftp4 一.打开关闭文件打开文件:vim /path/to/somefilev ...