ajax前臺(tái)后臺(tái)跨域請(qǐng)求處理方式
最近一直在搞公眾號(hào)前臺(tái)開(kāi)發(fā),遇到了ajax跨域請(qǐng)求的問(wèn)題,像地區(qū)的省-市-縣三級(jí)聯(lián)動(dòng)、汽車(chē)品牌-車(chē)系-車(chē)款的三級(jí)聯(lián)動(dòng)查詢(xún)等都需要調(diào)用外部接口(其他工程項(xiàng)目的接口)完成。下面就分享一下個(gè)人解決跨域請(qǐng)求的方案,當(dāng)然是在后臺(tái)程序猿大哥的幫助下,我才弄明白了其中的淵源,趕緊記錄下來(lái)慢慢積累,也希望對(duì)大家能有所幫助,還請(qǐng)積極提出意見(jiàn)或建議。
跨域請(qǐng)求需要借助后臺(tái)代碼接收callback回調(diào)函數(shù),對(duì)json數(shù)據(jù)進(jìn)行進(jìn)一步處理;前臺(tái)再用ajax請(qǐng)求向服務(wù)器發(fā)送callback參數(shù),并指定數(shù)據(jù)格式為jsonp。
一、后臺(tái)對(duì)跨域請(qǐng)求進(jìn)行處理
1.CarBrandController.java(汽車(chē)品牌接口java文件),這里列出的方法主要用來(lái)根據(jù)不同的level值查詢(xún)對(duì)應(yīng)的品牌、車(chē)系、車(chē)款,在這里對(duì)跨域請(qǐng)求做一個(gè)接收回調(diào)函數(shù)的處理,如果返回的callback為null,則不是跨域請(qǐng)求,不需要做特殊處理,直接打印json接口數(shù)據(jù)即可;如果返回的callback不為null,則表示跨域請(qǐng)求,這時(shí)要對(duì)json數(shù)據(jù)做一個(gè)特殊處理,即在json數(shù)據(jù)的外層加一對(duì)小括號(hào)包起來(lái),具體請(qǐng)看HttpAdapter.java文件中的printlnJSONObject方法。
public void json(HttpServletRequest request,HttpServletResponse response){
Map<String,Object>map=new HashMap<String, Object>();
String id = request.getParameter("id"); //接收ajax請(qǐng)求帶過(guò)來(lái)的id
String level = request.getParameter("level"); //接收ajax請(qǐng)求帶過(guò)來(lái)的level
String callback=request.getParameter("callback"); //接收ajax請(qǐng)求帶過(guò)來(lái)的callback參數(shù)
if ("1".equals(level)) { //如果level是'1',則查詢(xún)第一級(jí)目錄內(nèi)容
map.put("results", this.carBrandService.findByAttr(null, "first_letter asc")); //調(diào)用查詢(xún)方法,結(jié)果放入map
} else if ("2".equals(level)) { //如果level是'2',則查詢(xún)第二級(jí)目錄內(nèi)容
map.put("results", this.carSerieService.findByAttr("parent_id="+id, "first_letter asc"));//調(diào)用查詢(xún)方法,結(jié)果放入map
} else if ("3".equals(level)) { //如果level是'3',則查詢(xún)第三極目錄內(nèi)容
map.put("results", this.carModelYearService.findByAttr("parent_id="+id, "jian_pin desc"));//調(diào)用查詢(xún)方法,結(jié)果放入map
}
map.put("level",level);
if (null==callback) { //如果接收的callback值為null,則是不跨域的請(qǐng)求,輸出json對(duì)象
HttpAdapter.printlnObject(response, map);
}else{ //如果接收的callback值不為null,則是跨域請(qǐng)求,輸出跨域的json對(duì)象
HttpAdapter.printlnJSONPObject(response, map, callback);
}
}
2.HttpAdapter.java(輸出對(duì)象的java文件),printlnObject方法打印正常json字符串;printlnJSONObject方法對(duì)json字符串進(jìn)行了特殊處理。
/**
* 打印對(duì)象
* @param response
* @param object
*/
public static void printlnObject(HttpServletResponse response,Object object){
PrintWriter writer=getWriter(response);
writer.println(JSON.toJSONString(object));
}
/**
* 打印跨域?qū)ο?
* @param response
* @param object
*/
public static void printlnJSONPObject(HttpServletResponse response,Object object,String callback){
PrintWriter writer=getWriter(response);
writer.println(callback+"("+JSON.toJSONString(object)+")");
}
二、前臺(tái)ajax跨域請(qǐng)求數(shù)據(jù)
寫(xiě)法1:向服務(wù)器發(fā)送一個(gè)參數(shù)callback=?,同時(shí)指定dataType為'jsonp'的格式,跨域請(qǐng)求時(shí)指定的數(shù)據(jù)格式必須是jsonp的形式。
function loadData(obj,level,id,value){
$.ajax({
url:'http://192.168.1.106:8086/carBrand/json.html?level='+level+'&id='+id+'&callback=?', //將callback寫(xiě)在請(qǐng)求url后面作為參數(shù)攜帶
type:'GET',
async:false,
dataType:'jsonp',
success:function(data){
console.log(data);
//其他處理(動(dòng)態(tài)添加數(shù)據(jù)元素)
});
}
寫(xiě)法2:callback不需要寫(xiě)在url中,但是要指定jsonp參數(shù)為'callback',并給jsonpCallback參數(shù)一個(gè)值。
function loadData(obj,level,id,value){
$.ajax({
url:'http://192.168.1.106:8086/carBrand/json.html?level='+level+'&id='+id,
type:'GET',
dataType:'jsonp',
jsonp: 'callback', //將callback寫(xiě)在jsonp里作為參數(shù)連同請(qǐng)求一起發(fā)送
jsonpCallback:'jsonpCallback1',
success:function(data){
console.log(data);
}); }
以上兩種寫(xiě)法的含義是一樣的,只是寫(xiě)法不同罷了。
接下來(lái)補(bǔ)充一下jsonp的工作原理。
三、jsonp跨域的原理解析
jsonp的最基本的原理是:動(dòng)態(tài)添加一個(gè)<script>標(biāo)簽,而script標(biāo)簽的src屬性是沒(méi)有跨域的限制的。這樣說(shuō)來(lái),這種跨域方式其實(shí)與ajax XmlHttpRequest協(xié)議無(wú)關(guān)了.
JSONP是一個(gè)非官方的協(xié)議,它允許在服務(wù)器端集成Script tags返回至客戶(hù)端,通過(guò)javascript callback的形式實(shí)現(xiàn)跨域訪(fǎng)問(wèn)JSONP即JSON with Padding。由于同源策略的限制,XmlHttpRequest只允許請(qǐng)求當(dāng)前源(域名、協(xié)議、端口)的資源。如果要進(jìn)行跨域請(qǐng)求,我們可以通過(guò)使用html的script標(biāo)記來(lái)進(jìn)行跨域請(qǐng)求,并在響應(yīng)中返回要執(zhí)行的script代碼,其中可以直接使用JSON傳遞javascript對(duì)象。這種跨域的通訊方式稱(chēng)為JSONP。
jsonCallback 函數(shù)jsonp1236827957501(....): 是瀏覽器客戶(hù)端注冊(cè)的,獲取跨域服務(wù)器上的json數(shù)據(jù)后,回調(diào)的函數(shù)
Jsonp原理:
首先在客戶(hù)端注冊(cè)一個(gè)callback (如:'jsoncallback'), 然后把callback的名字(如:jsonp1236827957501)傳給服務(wù)器。注意:服務(wù)端得到callback的數(shù)值后,要用jsonp1236827957501(......)把將要輸出的json內(nèi)容包括起來(lái),此時(shí),服務(wù)器生成 json 數(shù)據(jù)才能被客戶(hù)端正確接收。
然后以 javascript 語(yǔ)法的方式,生成一個(gè)function , function 名字就是傳遞上來(lái)的參數(shù) 'jsoncallback'的值 jsonp1236827957501 .
最后將 json 數(shù)據(jù)直接以入?yún)⒌姆绞剑胖玫?function 中,這樣就生成了一段 js 語(yǔ)法的文檔,返回給客戶(hù)端。
客戶(hù)端瀏覽器,解析script標(biāo)簽,并執(zhí)行返回的 javascript 文檔,此時(shí)javascript文檔數(shù)據(jù),作為參數(shù),
傳入到了客戶(hù)端預(yù)先定義好的 callback 函數(shù)(如上例中jquery $.ajax()方法封裝的的success: function (json))里.(動(dòng)態(tài)執(zhí)行回調(diào)函數(shù))
可以說(shuō)jsonp的方式原理上和<script src="http://跨域/...xx.js"></script>是一致的(qq空間就是大量采用這種方式來(lái)實(shí)現(xiàn)跨域數(shù)據(jù)交換的) .JSONP是一種腳本注入(Script Injection)行為,所以也有一定的安全隱患.
注意,jquey是不支持post方式跨域的.
相關(guān)文章
js獲取input長(zhǎng)度并根據(jù)頁(yè)面寬度設(shè)置其大小及居中對(duì)齊
這篇文章主要介紹了js獲取input長(zhǎng)度并根據(jù)頁(yè)面寬度設(shè)置其大小及居中對(duì)齊的方法,需要的朋友可以參考下2014-08-08
Jquery實(shí)現(xiàn)的tab效果可以指定默認(rèn)顯示第幾頁(yè)
tab效果想必大家在網(wǎng)上都有見(jiàn)過(guò)很多吧,在本文將為大家介紹下如何實(shí)現(xiàn)可以在代碼里面指定默認(rèn)顯示第幾頁(yè)的tab效果,感興趣的朋友不要錯(cuò)過(guò)2013-10-10
前端js操作Cookie超詳細(xì)介紹與實(shí)戰(zhàn)案例
這篇文章主要給大家介紹了關(guān)于前端js操作Cookie詳細(xì)介紹與案例的相關(guān)資料,JS Cookie是一個(gè)用于在瀏覽器中操作Cookie的JavaScript庫(kù),它提供了一組簡(jiǎn)單的方法來(lái)設(shè)置、獲取、刪除和檢查 Cookie,需要的朋友可以參考下2023-09-09
JavaScript 異步調(diào)用框架 (Part 1 - 問(wèn)題 & 場(chǎng)景)
在Ajax應(yīng)用中,調(diào)用XMLHttpRequest是很常見(jiàn)的情況。特別是以客戶(hù)端為中心的Ajax應(yīng)用,各種需要從服務(wù)器端獲取數(shù)據(jù)的操作都通過(guò)XHR異步調(diào)用完成。2009-08-08
Javascript遍歷Html Table示例(包括內(nèi)容和屬性值)
這篇文章主要介紹了Javascript如何遍歷Html Table(包括內(nèi)容和屬性值),需要的朋友可以參考下2014-07-07
JavaScript 中如何實(shí)現(xiàn)并發(fā)控制
在日常開(kāi)發(fā)過(guò)程中,你可能會(huì)遇到并發(fā)控制的場(chǎng)景,比如控制請(qǐng)求并發(fā)數(shù)。那么在 JavaScript 中如何實(shí)現(xiàn)并發(fā)控制呢?在回答這個(gè)問(wèn)題之前,我們來(lái)簡(jiǎn)單介紹一下并發(fā)控制。2021-05-05

