火车时刻表WebApp

关键词 :Ajax 跨域访问 php 同源策略 JQueryMobile

前言

在面试的过程中,兄弟连的徐老师提出要求我用JQuery Mobile(前端框架)来实现一个具有“火车时刻表”功能的WebAPP。

在做的过程中,我遇到了

  1. Ajax——更底层地说是JavaScript——的跨域问题;
  2. 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:

https://www.baidu.com/link?url=lNW1dzH0BR-EwjQ74kSRXu7j1e-KPPFiwKeF7RYCt1XfloqBnAtE_HUjVCkgTdKsPFyELWHhXz2HRI3iK2KZoa&wd=&eqid=c9519bdb0000520a0000000355a314f9&qid=c9519bdb0000520a&bdlkc=1

本项目前台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

时间: 2024-10-31 19:45:14

火车时刻表WebApp的相关文章

java抓取12306火车余票信息

最近在弄一个微信的公众帐号,涉及到火车票查询,之前用的网上找到的一个接口,但只能查到火车时刻表,12306又没有提供专门的查票的接口.今天突然想起自己直接去12306上查询,抓取查询返回的数据包,这样就可以得到火车票的信息.这里就随笔记一下获取12306余票的过程. 首先,我用firefox浏览器上12306查询余票.打开firefox的Web控制台,选上网络中的"记录请求和响应主体" 然后输入地址日期信息之后点击网页上的查询按钮,就能在Web控制台下看到网页请求的地址了: 就是图片中

php webservice 接口 实例 机票航班时刻表

<?php header('Content-Type: text/html; charset=UTF-8'); $client = new SoapClient('http://webservice.webxml.com.cn/webservices/DomesticAirline.asmx?wsdl'); $fromcity=!empty($_POST['fromcity']) ? trim($_POST['fromcity']) : '长沙'; $tocity=!empty($_POST['

收藏点webservice接口

商业和贸易: 1.股票行情数据 WEB 服务(支持香港.深圳.上海基金.债券和股票:支持多股票同时查询) Endpoint: http://webservice.webxml.com.cn/WebServices/StockInfoWS.asmx Disco: http://webservice.webxml.com.cn/WebServices/StockInfoWS.asmx?disco WSDL: http://webservice.webxml.com.cn/WebServices/St

常用的服务

(1)天气预报: http://www.webxml.com.cn/WebServices/WeatherWebService.asmx (2)验证码图片        http://www.webxml.com.cn/WebServices/ValidateCodeWebService.asmx (3)中国邮政编码: http://www.webxml.com.cn/WebServices/ChinaZipSearchWebService.asmx (4) Email地址验证: http://

WebService 服务接口

天气预报Web服务,数据来源于中国气象局Endpoint :http://www.webxml.com.cn/WebServices/WeatherWebService.asmxDisco :http://www.webxml.com.cn/WebServices/WeatherWebService.asmx?discoWSDL :http://www.webxml.com.cn/WebServices/WeatherWebService.asmx?wsdl IP地址来源搜索 WEB 服务(是目

网络上可供测试的Web Service

腾讯QQ在线状态 WEB 服务Endpoint: http://www.webxml.com.cn/webservices/qqOnlineWebService.asmx Disco: http://www.webxml.com.cn/webservices/qqOnlineWebService.asmx?discoWSDL: http://www.webxml.com.cn/webservices/qqOnlineWebService.asmx?wsdl通过输入QQ号码(String)检测QQ

特殊网址

网络上可供测试的Web Service 腾讯QQ在线状态 WEB 服务 Endpoint: http://www.webxml.com.cn/webservices/qqOnlineWebService.asmx Disco: http://www.webxml.com.cn/webservices/qqOnlineWebService.asmx?disco WSDL: http://www.webxml.com.cn/webservices/qqOnlineWebService.asmx?ws

经常使用的webservice接口

Web Service 一些对外公开的网络服务接口 2011-10-29 14:12 商业和贸易: 1.股票行情数据 WEB 服务(支持香港.深圳.上海基金.债券和股票:支持多股票同一时候查询) Endpoint: http://webservice.webxml.com.cn/WebServices/StockInfoWS.asmx Disco: http://webservice.webxml.com.cn/WebServices/StockInfoWS.asmx?disco WSDL: h

Android和Linux应用综合对比分析

公开发布的序言: 这篇文章是作于2012年7月12日,也就是自己刚从大学校园迈向工作岗位的时候遇到的第一个题目"请你针对我们公司目前的应用行业场景做一下调研:在终端做应用程序开发的平台是选择Linux好还是Android好"而写的. 在踏出校园之前,自己从来没有接触过安卓的开发领域(除了在2010年下半年买了一部分安卓的智能手机外).接到这个题目后,自己也没有退缩,硬着头皮接下来了,然后凭借自己在学校时候学的一点检索信息写学术论文的小功底,三天之内写下了这篇长达1万4千多字的调研报告,