搞定所有的跨域请求问题
轉載自??搞定所有的跨域請求問題
網上各種跨域教程,各種實踐,各種問答,除了簡單的 jsonp 以外,很多說 CORS 的都是行不通的,老是缺那么一兩個關鍵的配置。本文只想解決問題,所有的代碼經過親自實踐。
本文解決跨域中的 get、post、data、cookie 等這些問題。
本文只會說 get 請求和 post 請求,讀者請把 post 請求理解成除 get 請求外的所有其他請求方式。
JSONP
jsonp 的原理很簡單,利用了【前端請求靜態資源的時候不存在跨域問題】這個思路。
但是?只支持 get,只支持 get,只支持 get。
注意一點,既然這個方法叫 jsonp,后端數據一定要使用 json 數據,不能隨便的搞個字符串什么的,不然你會覺得結果莫名其妙的。
前端 jQuery 寫法
$.ajax({type: "get",url: baseUrl + "/jsonp/get",dataType: "jsonp",success: function(response) {$("#response").val(JSON.stringify(response));} });dataType: "jsonp"。除了這個,其他配置和普通的請求是一樣的。
后端 SpringMVC 配置
如果你也使用 SpringMVC,那么配置一個 jsonp 的 Advice 就可以了,這樣我們寫的每一個 Controller 方法就完全不需要考慮客戶端到底是不是 jsonp 請求了,Spring 會自動做相應的處理。
@ControllerAdvice public class JsonpAdvice extends AbstractJsonpResponseBodyAdvice {public JsonpAdvice(){// 這樣如果請求中帶 callback 參數,Spring 就知道這個是 jsonp 的請求了super("callback");} }以上寫法要求?SpringMVC 版本不低于 3.2,低于 3.2 的我只能說,你們該升級了。
后端非 SpringMVC 配置
以前剛工作的時候,Struts2 還紅遍天,幾年的光景,SpringMVC 就基本統治下來了國內市場。
偷懶一下,這里貼個偽代碼吧,在我們的方法返回前端之前調一下 wrap 方法:
public Object wrap(HttpServletRequest request){String callback = request.getParameter("callback");if(StringUtils.isBlank(callback)){return result;} else {return callback+"("+JSON.toJSONString(result)+")";} }CORS
Cross-Origin Resource Sharing
畢竟 jsonp 只支持 get 請求,肯定不能滿足我們的所有的請求需要,所以才需要搬出 CORS。
國內的 web 開發者還是比較苦逼的,用戶死不升級瀏覽器,老板還死要開發者做兼容。
CORS 支持以下瀏覽器,目前來看,瀏覽器的問題已經越來越不重要了,連淘寶都不支持 IE7 了~
- Chrome 3+
- Firefox 3.5+
- Opera 12+
- Safari 4+
- Internet Explorer 8+
前端 jQuery 寫法
直接看代碼吧:
$.ajax({type: "POST",url: baseUrl + "/jsonp/post",dataType: 'json',crossDomain: true,xhrFields: {withCredentials: true},data: {name: "name_from_frontend"},success: function (response) {console.log(response)// 返回的 json 數據$("#response").val(JSON.stringify(response));} });dataType: "json",這里是 json,不是 jsonp,不是 jsonp,不是 jsonp。
crossDomain: true,這里代表使用跨域請求
xhrFields: {withCredentials: true},這樣配置就可以把 cookie 帶過去了,不然我們連 session 都沒法維護,很多人都栽在這里。當然,如果你沒有這個需求,也就不需要配置這個了。
后端 SpringMVC 配置
對于大部分的 web 項目,一般都會有 mvc 相關的配置類,此類繼承自 WebMvcConfigurerAdapter。如果你也使用 SpringMVC 4.2 以上的版本的話,直接像下面這樣添加這個方法就可以了:
@Configuration public class WebConfig extends WebMvcConfigurerAdapter {@Overridepublic void addCorsMappings(CorsRegistry registry) {registry.addMapping("/**/*").allowedOrigins("*");} }如果很不幸你的項目中 SpringMVC 版本低于 4.2,那么需要「曲線救國」一下:
public class CrossDomainFilter extends OncePerRequestFilter {@Overrideprotected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {response.addHeader("Access-Control-Allow-Origin", "*");// 如果提示 * 不行,請往下看response.addHeader("Access-Control-Allow-Credentials", "true");response.addHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE");response.addHeader("Access-Control-Allow-Headers", "Content-Type");filterChain.doFilter(request, response);} }在 web.xml 中配置下 filter:
<filter><filter-name>CrossDomainFilter</filter-name><filter-class>com.javadoop.filters.CrossDomainFilter</filter-class> </filter> <filter-mapping><filter-name>CrossDomainFilter</filter-name><url-pattern>/*</url-pattern> </filter-mapping>有很多項目用 shiro 的,也可以通過配置 shiro 過濾器的方式,這里就不介紹了。
注意了,我說的是很籠統的配置,對于大部分項目是可以這么籠統地配置的。文中類似 “*” 這種配置讀者應該都能知道怎么配。
如果讀者發現瀏覽器提示不能用 ‘*’ 符號,那讀者可以在上面的 filter 中根據 request 對象拿到請求頭中的 referer(request.getHeader("referer")),然后動態地設置 "Access-Control-Allow-Origin":
String referer = request.getHeader("referer"); if (StringUtils.isNotBlank(referer)) {URL url = new URL(referer);String origin = url.getProtocol() + "://" + url.getHost();response.addHeader("Access-Control-Allow-Origin", origin); } else {response.addHeader("Access-Control-Allow-Origin", "*"); }2018-04-28:今天終于知道為什么有時候會提示我們 * 不支持了,原來是只要前端寫了 withCredentials: true 那么瀏覽器就會提示這個,一種辦法就是這里說的使用動態構造 origin 的方式,另一種辦法就是跨域不傳 cookie,讓前端把 cookie 要傳的信息(如 sessionId/accessKey) 放到 header 中或者直接寫在 request 的參數里。
前端非 jQuery 寫法
jQuery 一招鮮吃遍天的日子是徹底不在了,這里就說說如果不使用 jQuery 的話,怎么解決 post 跨域的問題。大部分的 js 庫都會提供相應的方案的,大家直接找相應的文檔看看就知道怎么用了。
來一段原生 js 介紹下:
function createCORSRequest(method, url) {var xhr = new XMLHttpRequest();if ("withCredentials" in xhr) {// 如果有 withCredentials 這個屬性,那么可以肯定是 XMLHTTPRequest2 對象。看第三個參數xhr.open(method, url, true);} else if (typeof XDomainRequest != "undefined") {// 此對象是 IE 用來跨域請求的xhr = new XDomainRequest();xhr.open(method, url);} else {// 如果是這樣,很不幸,瀏覽器不支持 CORSxhr = null;}return xhr; }var xhr = createCORSRequest('GET', url); if (!xhr) {throw new Error('CORS not supported'); }其中,Chrome,Firefox,Opera,Safari 這些「程序員友好」的瀏覽器使用的是 XMLHTTPRequest2 對象。IE 使用的是 XDomainRequest。
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的搞定所有的跨域请求问题的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Redis+Tomcat+Nginx集群
- 下一篇: jar包天天见,可是你知道它的运行机制吗