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頁面的協議、域名、端口、子域名不同,所進行的訪問行動都是跨域的,而瀏覽器爲了安全問題一般都限制了跨域訪問,也就是不允許跨域請求資源。
以下情況存在跨域:
- 網絡協議不同,如http訪問https協議
- 端口不同,如80端口訪問8080端口
- 域名不同,如baidu.com訪問taobao.com
- 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>
注意如果項目中配置了檢測是否登錄過濾器,可能會起衝突,因爲沒有登錄的話每次都會跳轉到登錄接口.