Cordova移動應用對云端服務器數據庫的跨域訪問
當基于類似 Cordova這樣的跨平臺開發框架進行移動應用的跨平臺開發時,往往需要訪問部署在公網云端服務器上的數據庫,這時就涉及到了跨域數據訪問的問題。
文章目錄
- Cordova移動應用對云端服務器數據庫的跨域訪問
- 一、跨域訪問的概念
- 二、跨域訪問在Cordova中的實現實例
- 1、運行環境
- 2、實例
一、跨域訪問的概念
跨域(CORS, Cross-Origin Resource Sharing)指的是一個源(origin)的網頁或應用,訪問另一個源上的資源或接口時,就發生了“跨域”。跨域概念的起源是由于同源策略(Same-origin_policy),該策略是1995年由 Netscape 公司引入瀏覽器的最核心也是最基本的安全策略。同源指域名(IP)、協議、端口需要相同才能完成彼此資源的訪問和讀寫。而不同源的客戶端腳本在沒有明確授權的情況下,不允許讀寫對方的資源,瀏覽器會報異常:“拒絕訪問”。主要目的是避免在客戶不知情的情況下出現安全問題。
因此,跨域只要存在不同IP地址、不同域名(包括子域名)、不同端口地址,都屬于“跨域”訪問。例如:
跨域訪問 | 原因 |
---|---|
http://www.a.com/index.html 調用 http://www.b.com/server.php | 主域名不同 |
http://www.a.com/index.html 調用 http://www.b.com/server.php | 子域名不同 |
http://www.a.com/index.html 調用 http://www.b.com/server.php | 子域名不同 |
http://www.a.com:80/index.html 調用 http://www.a.com:8080/index.html | 端口不同 |
http://www.a.com/index.html 調用 https://www.a.com/server.php | 協議不同 |
然而,從上面實例可見,跨域訪問的需求在實際應用中普遍存在,特別是在當今互聯網已成為基礎設施的情況下,例如:
1、集團公司或組織下,多個子域間的資源共享和訪問
2、客戶端和服務端之間的遠程資源交互和訪問
3、跨平臺開發需要將數據集中在公網服務器,而移動客戶端通過遠程完成數據的共享和并發。
在上述場景中,都涉及到跨不同域名、IP或端口的訪問。
二、跨域訪問在Cordova中的實現實例
1、運行環境
本實例的運行開發環境基于如下架構:
(1) 公網WWW服務器
IP地址假設為:10.10.10.111
www服務:apache
后端開發語言:php
數據庫:mysql(mariaDB)
(2) 前端開發工具
javascript+Html+css
cordova
2、實例
本實例實現基于cordova 編譯運行的跨平臺移動app,訪問公網10.10.10.1中安裝的數據庫中的users表,當用戶輸入username,userpassword后,選擇“新用戶注冊”,則向數據庫表中新增一條用戶,未選中,則查詢表中是否存在uname和upass分別等于用戶輸入的username和userpassword的記錄。
users表結構如下:
生成庫的SQL語句:
DROP TABLE IF EXISTS `users`;
CREATE TABLE `users` (`id` int(11) NOT NULL AUTO_INCREMENT,`uname` char(30) NOT NULL,`upass` varchar(30) DEFAULT NULL,`utype` tinyint(1) DEFAULT '0',PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=13 DEFAULT CHARSET=utf8;
(1)前端代碼
cordova工程中index.html內容如下:
其中使用了jqueryMobile,下載后需要放到www目錄下的lib目錄
<!--This is for mobile -->
<!DOCTYPE html>
<html><head><meta charset="utf-8"><title>Web SQLite Test</title><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="stylesheet" href="lib/jquery.mobile-1.4.5.min.css" /><script src="lib/jquery-2.1.1.min.js"></script><script src="lib/jquery.mobile-1.4.5.min.js"></script><!--<script type="text/javascript" charset="utf-8" src="cordova.js">--></script><script type="text/javascript">$(document).ready(function() {$("#submitbtn").bind("click", function () {$.ajax({type: "post",url: "http://10.10.10.111/myUserlogin_Server/valid.php",//公網云服務器地址data: {username:$('#username').val(),password:$('#userpassword').val(),registerit:$("#newuser").prop("checked"),},datatype: "jsonp",success : onSuccess, error : onError });return false;});}); function onSuccess(data,status){ data = $.trim(data); //去掉前后空格 alert(data);} function onError(data,status){ //進行錯誤處理 console.info("網絡出錯");} </script> </head><body><div data-role="page"><div data-role="header"><h1>系統登錄</h1></div><div data-role="content" class="ui-content"><form method="post" id="feedbackform"><div class="ui-field-contain"><label for="username">用戶名:</label><input type="text" name="username" id="username" placeholder="請輸入用戶名"> <label for="userpassword">密   碼:</label><input type="password" name="userpassword" id="userpassword" placeholder="請輸入密碼"><label for="newuser">新用戶注冊</label><input type="checkbox" name="newuser" id="newuser" value="1"></div><input type="button" id="submitbtn" class="ui-btn ui-btn-a" value="提交"></form><button id="ModifyRec" >取消</button><div id="database_results"></div></div> </body></html>
(2)后端代碼
在服務器中,安裝了apache+php的解釋器,并在htdocs中建立文件夾myUserlogin_Server,里面的valid.php用于根據前端提交的數據完成數據庫的相應操作。
<?php
header("Access-Control-Allow-Origin:*");//允許所有域名的腳本跨域訪問該資源,從安全角度建議設置更嚴格的權限
$user=$_POST["username"];
$pass=$_POST["password"];
$newuser=$_POST["registerit"];
/*echo '用戶名:'.$user;
echo '密碼:'.$pass;
echo '是否需注冊:'.$newuser;*/
// PDO方式連接
try {$conn = new PDO("mysql:host=localhost;dbname=cordovatestdb", '登錄用戶名', '登錄密碼');// echo "連接mysql的test數據庫成功";
}
catch (PDOException $e) { die('連接失敗:' . $e->getMessage()); }
$conn->exec("set names 'utf8'");
if($newuser=='true') //注冊新用戶{$sql = "SELECT id, uname, utype FROM users where uname=?";if (QueryDB($conn,$sql,array($user))!=null){//已有同名記錄echo "已經注冊過,直接登錄!"; } else { //進行注冊,新增該用戶$sql = "INSERT INTO users (uname, upass, utype)VALUES (?, ?, 1)";$stmt = $conn->prepare($sql);$rs = $stmt->execute(array($user,$pass));if ($rs) {echo "按輸入的用戶名和密碼,注冊成功!";$sql = "SELECT id, uname, utype FROM users where uname=? and upass=?";$rows = QueryDB($conn,$sql,array($user,$pass));if ($rows!=null){//驗證注冊記錄是否保存成功print_r($rows); //輸出記錄} else {echo "注冊失敗: " . $sql . "<br>" . $conn->error;}}}}
else{ //登錄$sql = "SELECT id, uname, utype FROM users where uname=? and upass=?";$rows = QueryDB($conn,$sql,array($user,$pass));if ($rows!=null){//登錄驗證記錄存在// 驗證用戶成功,輸出數據echo "登錄成功!"; print_r($rows); }else {echo "用戶名或者密碼錯誤!";}}
$conn = null; Function QueryDB($dbo,$sql,$paraStr)
{$stmt = $dbo->prepare($sql);$rs = $stmt->execute($paraStr);$rows = $stmt->fetchAll(); $row_count = $stmt->rowCount(); //記錄數if ($rs && $row_count>0)return $rows;else {return 0;}
}
?>
注意:前端代碼也可以直接采用javascript的fetch語句完成http請求。
參考代碼如下:
const apiURL = "https://10.10.10.111/valid.php"; // 你的PHP地址function login() {const username = document.getElementById("username").value;const userpassword = document.getElementById("userpassword").value;const registerit = document..getElementById("newuser").checked;fetch(apiURL, {method: "POST",headers: {"Content-Type": "application/json"},body: JSON.stringify({username: username,password: userpassword,registerit: registerit})}).then(response => response.json()).then(data => {if (data.success) {alert("登錄成功!");// 繼續處理登錄后的邏輯} else {alert("登錄失敗:" + data.message);}}).catch(error => {alert("請求出錯:" + error);});
}