CORS跨域訪問錯誤:No ‘Access-Control-Allow-Origin’ header is present on the requested resource

                    CORS跨域訪問錯誤:No ‘Access-Control-Allow-Origin’ header is present on the requested resource

1.什麼是跨域訪問:

   由於瀏覽器同源策略(瀏覽器不能執行其他網站的腳本),是瀏覽器對javascript施加的安全限制。凡是發送url請求的協議、域名、端口之間任意一個與當前頁面地址不同的即爲跨域。

注意:跨域限制訪問,其實是瀏覽器的限制localhost和127.0.0.1雖然都指向本機,但也屬於跨域。瀏覽器執行javascript腳本時,會檢查這個腳本屬於哪個頁面,如果不是同源頁面,就不會被執行。

同源策略:是指協議,域名,端口都要相同,其中有一個不同都會產生跨域;

舉例而言:

a頁面想獲取b頁面資源,如果a、b頁面的協議、域名、端口、子域名不同,所進行的訪問行動都是跨域的,而瀏覽器爲了安全問題一般都限制了跨域訪問,也就是不允許跨域請求資源。

以下情況存在跨域:

  1. 網絡協議不同,如http訪問https協議
  2. 端口不同,如80端口訪問8080端口
  3. 域名不同,如baidu.com訪問taobao.com
  4. Ip地址不同

2. 解決方法(跨域請求資源的方法):

(1)proxy代理:

  proxy代理用於將請求發送給後臺服務器,通過服務器來發送請求,然後將請求的結果傳遞給前端。

通過nginx代理:用nginx作爲代理服務器和用戶交互,當用戶發送一個不同域的ip時,會被nginx轉發到相同域上服務。

#
# Wide-open CORS config for nginx
#
location / {
     if ($request_method = 'OPTIONS') {
        add_header 'Access-Control-Allow-Origin' '*';
        add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
        #
        # Custom headers and headers various browsers *should* be OK with but aren't
        #
        add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
        #
        # Tell client that this pre-flight info is valid for 20 days
        #
        add_header 'Access-Control-Max-Age' 1728000;
        add_header 'Content-Type' 'text/plain charset=UTF-8';
        add_header 'Content-Length' 0;
        return 204;
     }
     if ($request_method = 'POST') {
        add_header 'Access-Control-Allow-Origin' '*';
        add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
        add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
     }
     if ($request_method = 'GET') {
        add_header 'Access-Control-Allow-Origin' '*';
        add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
        add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
     }
}

2)(建議)CORS (cross-origin Resource Sharing)是現代瀏覽器支持資源請求的一種最常用的方式。即需要後端人員在處理請求數據時,添加允許跨域的操作。使用自定義的HTTP頭部允許瀏覽器和服務器相互瞭解對方,從而決定請求或響應成功與否。與後臺配置基本相同,都是通過過濾器在Response中返回頭部,使服務器和瀏覽器可互通。原理:利用瀏覽器對Access-Control-Allow-Origin的支持,但有些瀏覽器不支持。

Access-Control-Allow-Origin:指定授權訪問的域
Access-Control-Allow-Methods:授權請求的方法(GET, POST, PUT, DELETE,OPTIONS等)

  "Content-Type": "text/html; charset=UTF-8",
  "Access-Control-Allow-Origin":'http://localhost',
  "Access-Control-Allow-Methods": 'GET, POST, OPTIONS',
  "Access-Control-Allow-Headers": 'X-Requested-With, Content-Type'

 適合設置單一的(或全部)授權訪問域,所有配置都是固定的,比較簡單。


 
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
 
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
 
/**
 * Created by 12143 on 2018/12/7.
 */
@Component
public class CORSFilter extends OncePerRequestFilter {
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        response.addHeader("Access-Control-Allow-Origin", "*");
       //response.addHeader("Access-Control-Allow-Origin", "http://192.168.100.150:8020");
        response.addHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE");
        response.addHeader("Access-Control-Allow-Headers", "Content-Type");
        response.addHeader("Access-Control-Max-Age", "1800");//30 min
        filterChain.doFilter(request, response);
    }
}

Access-Control-Allow-Origin爲*則允許所有url訪問,如果爲“http://192.168.100.150:8020”則只有此url才能訪問,注意有端口的要把端口也寫上,比如配置了http://192.168.56.130:8081,那麼只有http://192.168.56.130:8081 能拿到數據,否則全部報403異常


然後在web.xml中添加此過濾器:

<filter>
    <filter-name>CorsFilter</filter-name>
    <filter-class>com.xxx.common.filter.CORSFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>CorsFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

 

(3)jsonp是解決前端跨域的方法。原理是html中link,href,src屬性不受跨域影響,link可以調用遠程的css文件,href可以鏈接到隨便的url上。圖片的src可以隨意引用圖片。JSONP其實就是JSON另外一種的使用模式,可以用JSONP去解決跨域訪問的問題

通過動態插入一個script標籤,瀏覽器對script的資源引用沒有同源限制,同時資源記載到頁面會立即執行。通過動態創建script來讀取他域的動態資源,獲取的數據一般爲json格式。


<body>
	<script type="text/javascript">
		function func1(ret){
			console.log(ret)
		}
		
	</script>
	<script src="http://192.168.100.150:8081/zhxZone/webmana/dict/jsonp?callback=func1" type="text/javascript" charset="utf-8"></script>
</body>
————————————————
版權聲明:本文爲CSDN博主「lianzhang861」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/lianzhang861/article/details/84871369

後端java處理 

@ResponseBody
@RequestMapping(value = "jsonp", produces = "text/plain;charset=UTF-8")
public void jsonp(String callback, HttpServletRequest req, HttpServletResponse res) {
    List<Map<String,Object>> list = new ArrayList<Map<String,Object>>();
    RetBase ret=new RetBase();
    try {
        res.setContentType("text/plain");
        res.setHeader("Pragma", "No-cache");
        res.setHeader("Cache-Control", "no-cache");
        res.setDateHeader("Expires", 0);
        Map<String,Object> params = new HashMap<String,Object>();
        list = dictService.getDictList(params);
        ret.setData(list);
        ret.setSuccess(true);
        ret.setMsg("獲取成功");
        PrintWriter out = res.getWriter();
        //JSONObject resultJSON = JSONObject.fromObject(ret); //根據需要拼裝json
        out.println(callback+"("+JSON.toJSONString(ret)+")");//返回jsonp格式數據
        out.flush();
        out.close();
    } catch (Exception e) {
        e.printStackTrace();
    }
}
————————————————
版權聲明:本文爲CSDN博主「lianzhang861」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/lianzhang861/article/details/84871369

使用jquery封裝的jsonp,使用起來相對簡單

使用起來跟使用ajax類似,只是dataType變成了jsonp,且增加了jsonp參數,參數就是上述的callback參數,不需要管他是啥值,因爲jquery自動給你起了個名字傳到後臺,並自動幫你生成回調函數並把數據取出來供success屬性方法來調用

jq jsonp標準寫法:


$.ajax({
    type: 'get',
    url: "http://192.168.100.150:8081/zhxZone/webmana/dict/jsonp",
    dataType: 'jsonp',
    jsonp:"callback",
    async:true,
    data:{
        
    },
    success: function(ret){
        console.log(ret)
    },
    error:function(data) {
    },

————————————————
版權聲明:本文爲CSDN博主「lianzhang861」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/lianzhang861/article/details/84871369

這裏針對ajax與jsonp的異同再做一些補充說明:

1、ajax和jsonp這兩種技術在調用方式上”看起來”很像,目的也一樣,都是請求一個url,然後把服務器返回的數據進行處理,因此jquery框架都把jsonp作爲ajax的一種形式進行了封裝。

2、但ajax和jsonp其實本質上是不同的東西。ajax的核心是通過XmlHttpRequest獲取非本頁內容,而jsonp的核心則是動態添加
 

 (4)後臺配置解決跨域

比如項目中用的是 maven,spring mvc/Springboot,首先在pom.xml中引入依賴

<!--跨域依賴-->
<dependency>
    <groupId>com.thetransactioncompany</groupId>
    <artifactId>cors-filter</artifactId>
    <version>1.7.1</version>
</dependency>
<dependency>
    <groupId>com.thetransactioncompany</groupId>
    <artifactId>java-property-utils</artifactId>
    <version>1.9</version>
</dependency>
<dependency>

 然後在web.xml配置過濾器

<!--爲了允許跨域訪問-->
<filter>
    <filter-name>CorsFilter</filter-name>
    <filter-class>com.thetransactioncompany.cors.CORSFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>CorsFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

注意如果項目中配置了檢測是否登錄過濾器,可能會起衝突,因爲沒有登錄的話每次都會跳轉到登錄接口. 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章