一.編一個服務器端servlet
@RequestMapping("/haha") @ResponseBody String haha(String haha, HttpServletRequest req, HttpServletResponse resp) { //resp.addHeader("Access-Control-Allow-Origin", "null"); System.out.println(haha); System.out.println("you accessed!!!"); return haha + " : " + req.getMethod(); }
如果服務器回復的頭部Access-Control-Allow-Origin屬性中包含請求的Origin,那么客戶端就可以通過ajax訪問.
我用的是spring mvc,如果RequestMapping不帶參數,默認為'/',相當於映射一切url;如果請求的url找不到,那就去找它.
無參數的RequestMapping只允許有一個,否則無法部署,報錯.因為最后兜底的只能有一個servlet.
在spring mvc中,如果沒有規定請求方式,默認是都可以,無論是get還是post都能夠找到資源,只要url正確就行.
二.ajax方式請求
1.如果設置了頭部就會出錯(ajax設置了headers就會出錯)
Response to preflight request doesn't pass access control check:
No 'Access-Control-Allow-Origin' header is present on the requested resource.
Origin 'null' is therefore not allowed access. The response had HTTP status code 403.
preflight意為起飛前,航前,pre 在...之前,flight航班
請求在起飛前沒有通過,請求被扼殺在搖籃里.
2.如果不設置頭部,可以把請求發送出去
No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'null' is therefore not allowed access.
下面用ajax請求這個servlet
<body> <h1 id='resp'></h1> <input id='haha' type='text'></input> </body> <script type="text/javascript"> $('#haha').keydown(function(event) { console.log(event.which) if(event.which==13){ $.get('http://localhost:8080/news/haha',{'haha':'wyf'},function(data){ console.log(data) console.log('get over') }) } }); </script>
服務器端輸出了"you succeed!!!",這說明對於跨域請求服務器是搭理了的,問題出在服務器禁止返回或者是瀏覽器不允許用戶查看返回的內容.
據我猜測,很有可能是后者,即:chrome分析返回結果,發現跨域了,於是不讓用戶看了.
如果用java代碼通過httpclient或者urlConnection來實現,是能夠收到回復的.所以很有可能,結果返回來了,瀏覽器不讓看.
三.解決方案之修改服務器
只需要在服務器上添加一句允許Origin就可以了,如果允許任何一個網站訪問,那么就設置為'*'就可以了.
resp.addHeader("Access-Control-Allow-Origin", "null");
四.解決方案之虛擬表單
解決方案很簡單:編一個表單進行提交,因為只有ajax才存在跨域訪問問題,而提交表單跟ajax不一樣.
提交表單之后服務器端決定了瀏覽器端頁面的跳轉,把權力完全交給了服務器,而ajax只是通過服務器獲取數據
下面的表單是可以提交成功的
<form action='http://localhost:8080/news/haha' method="GET"> <input id='haha' type='text'></input> <input type="submit"></input> </form>
可是填寫表單太麻煩,於是可以虛擬表單並提交
$(document).ready(function(){ var form=$('<form></form>') $(form).attr({"action":'http://localhost:8080/news/haha',"method":'post'}).append("<input name='haha' value='haha weidiao'>") $(form).submit() console.log('haha') })
五.同源策略
同源策略(Same-Origin Policy)阻止從一個源加載的文檔或腳本獲取或設置另一個源加載的文檔的屬性。如果它們的協議、端口(如果指明了的話)和主機名都相同。則他們屬於同源。
同源策略就是禁止外人訪問我的資源,是一種安全機制.它是瀏覽器采用的策略.
六.jsonp
<html xmlns="http://www.w3.org/1999/xhtml" > <head> <title>Test Jsonp</title> <script type="text/javascript"> function jsonpCallback(result) { alert(result.msg); } </script> <script type="text/javascript" src="http://test.com/test.php?jsonp=jsonpCallback"></script> </head> <body> </body> </html> 服務端的代碼: <?php echo $_GET['jsonp']."({msg:'this is json data'})"; ?>
從JSONP的原理來看的話,script標簽只能GET方式。還有就是后台程序需要對callback參數進行有效性過濾,不然惡意用戶可以插入攻擊代碼了。一般使用正則:
^[a-z0-9_]+$
來判斷用戶的回調函數名是否合法。
七.瀏覽器不讓看
chrome 等瀏覽器 對於 跨域請求並要求設置Headers自定義參數的時候的 "預請求" 就是如果遇到 跨域並設置headers的請求,所有請求需要兩步完成!
A 第一步:發送預請求 OPTIONS 請求。此時 服務器端需要對於OPTIONS請求作出響應 一般使用202響應即可 不用返回任何內容信息。
B 第二步:服務器accepted 第一步請求后 瀏覽器自動執行第二步 發送真正的請求。此時 大多數人 會發現請求成功了,但是 有那么幾個人會發現 請求成功了但是沒有任何信息返回 why?因為你自定義的請求頭在服務器響應中不存在!