【黑馬程序員濟(jì)南中心】跨域請求之JSONP、CORS淺談

1.為什么會有跨域?

? ?? ?隨著軟件開發(fā)分工趨于精細(xì),前后端開發(fā)分離成為趨勢,前端同事負(fù)責(zé)前端頁面的展示及頁面邏輯處理,服務(wù)端同事負(fù)責(zé)業(yè)務(wù)邏輯處理同時(shí)通過API為前端提供數(shù)據(jù)也為前端提供數(shù)據(jù)的持久化能力,考慮到前后端同事開發(fā)工具和習(xí)慣的不同,必然需要將前后端項(xiàng)目進(jìn)行獨(dú)立,再者考慮到網(wǎng)站訪問速度的問題,需要將靜態(tài)資源部署到CDN服務(wù)器上這樣項(xiàng)目分離也成為了必然。然而項(xiàng)目分離部署分離帶來的問題就是跨域請求的問題。

本例對比較流行的兩種跨域訪問方式(Jsonp和CORS)進(jìn)行討論。(注:示例代碼附在文章末尾處)

1.JSONP

? ?? ?JSONP是利用瀏覽器對script的資源引用沒有同源限制,通過動態(tài)插入一個(gè)script標(biāo)簽,當(dāng)資源加載到頁面后會立即執(zhí)行的原理實(shí)現(xiàn)跨域的。JSONP是一種非正式傳輸協(xié)議,該協(xié)議的一個(gè)要點(diǎn)就是允許用戶傳遞一個(gè)callback或者開始就定義一個(gè)回調(diào)方法,參數(shù)給服務(wù)端,然后服務(wù)端返回?cái)?shù)據(jù)時(shí)會將這個(gè)callback參數(shù)作為函數(shù)名來包裹住JSON數(shù)據(jù),這樣客戶端就可以隨意定制自己的函數(shù)來自動處理返回?cái)?shù)據(jù)了。

  JSONP只支持GET請求而不支持POST等其它類型的HTTP請求,它只支持跨域HTTP請求這種情況,不能解決不同域的兩個(gè)頁面之間如何進(jìn)行JavaScript調(diào)用的問題,JSONP的優(yōu)勢在于支持老式瀏覽器,弊端也比較明顯:需要客戶端和服務(wù)端定制進(jìn)行開發(fā),服務(wù)端返回的數(shù)據(jù)不能是標(biāo)準(zhǔn)的Json數(shù)據(jù),而是callback包裹的數(shù)據(jù)。

2.CORS

  CORS是現(xiàn)代瀏覽器支持跨域資源請求的一種方式,全稱是"跨域資源共享"(Cross-origin resource sharing),當(dāng)使用XMLHttpRequest發(fā)送請求時(shí),瀏覽器發(fā)現(xiàn)該請求不符合同源策略,會給該請求加一個(gè)請求頭:Origin,后臺進(jìn)行一系列處理,如果確定接受請求則在返回結(jié)果中加入一個(gè)響應(yīng)頭:Access-Control-Allow-Origin;瀏覽器判斷該相應(yīng)頭中是否包含Origin的值,如果有則瀏覽器會處理響應(yīng),我們就可以拿到響應(yīng)數(shù)據(jù),如果不包含瀏覽器直接駁回,這時(shí)我們無法拿到響應(yīng)數(shù)據(jù)。

? ?? ?CORS與JSONP的使用目的相同,但是比JSONP更強(qiáng)大,CORS支持所有的瀏覽器請求類型,承載的請求數(shù)據(jù)量更大,開放更簡潔,服務(wù)端只需要將處理后的數(shù)據(jù)直接返回,不需要再特殊處理。

? ?? ?1.不需要操作cookie

? ?? ?? ?? ?? ? 只需要設(shè)置:setHeader("Access-Control-Allow-Origin","url/*")

? ?? ?2.如果需要操作cookie

? ?? ?? ?? ?? ? 前臺:js需要增加參數(shù):{'withCredentials':true}

? ?? ?? ?? ?? ? 后臺:

? ?? ?? ?? ?? ?? ?? ?? ?setHeader("Access-Control-Allow-Origin","url") //注意:地址不能使用"*"代表所有

? ?? ?? ?? ?? ?? ?? ?? ?setHeader("Access-Control-Allow-Credentials","true") //支持操作cookie

? ?? ???注解方式:spring4.2版本以后提供了對跨域注解的支持,可以使用注解 @CorsOrigin

因需要實(shí)現(xiàn)跨域請求,跨域可以是:協(xié)議不一樣,域名不一樣,ip地址不一樣,端口號不一樣等多種情況。為了簡單,下面示例代碼使用tomcat服務(wù)器,端口號不同,分別部署兩個(gè)項(xiàng)目,項(xiàng)目之間進(jìn)行數(shù)據(jù)交互,驗(yàn)證跨域請求.

2個(gè)項(xiàng)目,展示如下:


1.JSONP示例代碼:

1.1jsonp前端代碼:(注:代碼在demo1項(xiàng)目中)

function jsonpTest1() {//傳統(tǒng)支持jsonp的方案

? ? ? ? $.ajax({

? ? ? ? url: 'http://localhost:8081/jsonp_demo2/jsonp/test1.do',

? ? ? ? dataType: 'jsonp',

? ? ? ? success: function (res, status, xhr) {

? ? ? ? ? ? ? ? alert(status);

? ? ? ? ? ? ? ? alert(res.msg);

? ? ? ? }

? ? });

}

function jsonpTest2() {//使用MappingJacksonValue,從spring4.1以后版本才可以使用

? ? ? ? $.ajax({

? ? ? ? url: 'http://localhost:8081/jsonp_demo2/jsonp/test2.do',

? ? ? ? dataType: 'jsonp',

? ? ? ? success: function (res, status, xhr) {

? ? ? ? ? ? ? ? alert(status);

? ? ? ? ? ? ? ? var resJson = $.parseJSON(res);

? ? ? ? ? ? ? ? alert(resJson.msg);

? ? ? ? }

? ? });

}

1.2jsonp后臺代碼:(注:代碼在demo2項(xiàng)目中)

/**

* @author:admin

* 20182018年3月30日上午11:03:03

*/

/**

* 描述:

* @author zhuan

* @version 2018年3月30日 上午11:03:03

*/

package com.itcast.controller;

import org.apache.commons.lang3.StringUtils;

import org.springframework.http.converter.json.MappingJacksonValue;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RestController;

import org.springframework.http.MediaType;

/**

* JS跨域解決方案一

* 描述:JSONP跨域請求controller

* @author zhuan

* @version 2018年3月31日 上午9:58:50

*/

@RestController

@RequestMapping("/jsonp")

public class JsonpController{


? ? ? ? /**

? ? ? ? *

? ? ? ? * 描述:傳統(tǒng)支持jsonp的方案

? ? ? ? * @param param

? ? ? ? * @param callback

? ? ? ? * @return

? ? ? ? */

? ? ? ? @RequestMapping(value = "/test1", produces = MediaType.APPLICATION_JSON_VALUE + ";charset=utf-8")

? ? ? ? public String jsonTest1(String param, String callback) {

? ? ? ? ? ? ? ? if (StringUtils.isNotBlank(callback)) {

? ? ? ? ? ? ? ? ? ? ? ? // 客戶端為jsonp請求。需要返回js代碼

? ? ? ? ? ? ? ? ? ? ? ? String jsonResutl = callback + "({\"type\":\"json\",\"msg\":\"test1 jsonp request success\"})";

? ? ? ? ? ? ? ? ? ? ? ? return jsonResutl;

? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? return "{\"type\":\"json\",\"msg\":\"test1 json request success\"}";

? ? ? ? }

? ? ? ? /**

? ? ? ? *

? ? ? ? * 描述:從spring4.1以后版本才可以使用

? ? ? ? *

? ? ? ? * @param param

? ? ? ? * @param callback

? ? ? ? * @return

? ? ? ? */

? ? ? ? @RequestMapping("/test2")

? ? ? ? public Object jsonTest2(String param,String callback){

? ? ? ? ? ? ? ? if(StringUtils.isNotBlank(callback)){

? ? ? ? ? ? ? ? ? ? ? ? MappingJacksonValue mappingJacksonValue = new MappingJacksonValue("{\"type\":\"jsonp\",\"msg\":\"test2 jsonp request success\"}");

? ? ? ? ? ? ? ? ? ? ? ? //設(shè)置回調(diào)方法

? ? ? ? ? ? ? ? ? ? ? ? mappingJacksonValue.setJsonpFunction(callback);

? ? ? ? ? ? ? ? ? ? ? ? return mappingJacksonValue;

? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? return "{\"type\":\"json\",\"msg\":\"test2 json request success\"}";

? ? ? ? }

}

2.CORS示例代碼:

2.1cors前端代碼:(注:代碼在demo1項(xiàng)目中)

function corsTest() {

? ? ? ? $.ajax({

? ? ? ? url: 'http://localhost:8081/jsonp_demo2/cors/test.do',

? ? ? ? dataType: 'json',

? ? ? ? success: function (res, status, xhr) {

? ? ? ? ? ? ? ? alert(status);

? ? ? ? ? ? ? ? alert(res.msg);

? ? ? ? }

? ? });

}

2.2cors后臺代碼:(注:代碼在demo2項(xiàng)目中)

package com.itcast.controller;

import org.springframework.web.bind.annotation.CrossOrigin;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RestController;

/**

* JS跨域解決方案二 描述:CORS跨域請求controller

*

* @author zhuan

* @version 2018年3月31日 上午9:58:50

*/

@RestController

@RequestMapping("/cors")

public class CorsController {

? ? ? ? // 1.不支持操作cookie

? ? ? ? // 只需要設(shè)置:setHeader("Access-Control-Allow-Origin","url/*")

? ? ? ? // 2.支持操作cookie

? ? ? ? // 前臺:

? ? ? ? // js需要增加參數(shù):{'withCredentials':true}

? ? ? ? // 后臺:

? ? ? ? // setHeader("Access-Control-Allow-Origin","url") //注意:地址不能使用"*"代表所有

? ? ? ? // setHeader("Access-Control-Allow-Credentials","true") //支持操作cookie

? ? ? ? // 注解方式:spring4.2版本以后提供了對跨域注解的支持 @CorsOrigin

? ? ? ? /**

? ? ? ? *

? ? ? ? * 描述:

? ? ? ? *

? ? ? ? * @param param

? ? ? ? * @param callback

? ? ? ? * @return

? ? ? ? */

? ? ? ? @RequestMapping("/test")

? ? ? ? @CrossOrigin(origins = "http://localhost:8080")

? ? ? ? public String corsTest1(String param) {

? ? ? ? ? ? ? ? return "{\"type\":\"json\",\"msg\":\"cors json request success\"}";

? ? ? ? }

}

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容