(五)JavaScript关于浏览器--ajax
五、ajax
Asynchronous JavaScript and XML:就是用JavaScript执行异步网络请求。
如一个form表单的提交,一旦“submit”后,表单提交(点击按钮一般是先触发onsubmit,在提交到action),就会跳转到action页面;这是因为在web中一次HTTP请求对应一个页面。
而如果用JavaScript发送这个请求,接收到数据后,再用JavaScript更新页面,用户就感觉自己仍然停留在原来的页面,但是数据却可以不断地更新。
AJAX主要依靠XMLHttpRequest
对象:点击打开链接
默认情况下,JavaScript在发送AJAX请求时,URL的域名必须和当前页面完全一致。完全一致的意思是,域名要相同(
www.example.com
和
example.com
不同),协议要相同(
http
和
https
不同),端口号要相同(默认是
:80
端口,它和
:8080
就不同)。
跨域原因由于安全限制(同源策略, 即JavaScript或Cookie只能访问同域下的内容).
JavaScript请求跨域的两种方式,方法:
1.JSONP (JSON with Padding),它允许在服务器端集成Scripttags返回至客户端,通过javascript callback的形式实现跨域访问(这仅仅是JSONP简单的实现形式)。但是,它有个限制,只能用GET请求,并且要求返回JavaScript。这种方式跨域实际上是利用了浏览器允许跨域引用JavaScript资源:
<scriptsrc="http://example.com/abc.js"></script>
通过script标签实现跨域请求,然后在服务端输出JSON数据并执行回调函数,从而解决了跨域的数据请求。(找了一段代码)
跨域访问:http://www.runoob.com/try/ajax/jsonp.php?jsoncallback=callbackFunction
<?php
header('Content-type: application/json');
//获取回调函数名 注册回调函数
$jsoncallback = htmlspecialchars($_REQUEST ['jsoncallback']);
//json数据
$json_data = '["customername1","customername2"]';
//输出jsonp格式的数据
echo $jsoncallback . "(" . $json_data . ")";
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>JSONP 实例</title>
</head>
<body>
<div id="divCustomers"></div>
<script type="text/javascript">
function callbackFunction(result, methodName)
{
var html = '<ul>';
for(var i = 0; i < result.length; i++)
{
html += '<li>' + result[i] + '</li>';
}
html += '</ul>';
document.getElementById('divCustomers').innerHTML = html;
}
</script>
<script type="text/javascript" src="http://www.runoob.com/try/ajax/jsonp.php?jsoncallback=callbackFunction"></script>
</body>
</html>
2.CORS 允许一个域上的网络应用向另一个域提交跨域AJAX 请求。实现此功能非常简单,只需由服务器发送一个响应标头即可。
http://www.test1.com打算从http://www.test2.com 请求数据。如果我们直接使用 AJAX 来请求将会失败;利用 CORS,http://www.test2.com 只需添加一个标头,就可以允许来自 http://www.test1.com 的请求:(*为允许任何域请求,可以改为http://www.test1.com)
// 所以如果在服务端代码中设置:这样的话任何域名都可以请求你的服务器了
header(“Access-Control-Allow-Origin:*”);
或者在要请求的域的服务器web.xml中配置,该过滤器可以通过添加必需的访问控制请求头Access-Control-*对象来进行跨域。同时还可以对一些请求进行拦截。如果请求是无效的,或者是不被允许的,该请求被拒绝或者禁止。
<filter>
<filter-name>CorsFilter</filter-name>
<filter-class>org.apache.catalina.filters.CorsFilter</filter-class>
<init-param>
<param-name>cors.allowed.origins</param-name>
<param-value>
http://localhost:8080,
https://localhost:8443
</param-value>
</init-param>
<init-param>
<param-name>cors.allowed.methods</param-name>
<param-value>
GET,POST,HEAD,OPTIONS,PUT
</param-value>
</init-param>
<init-param>
<param-name>cors.allowed.headers</param-name>
<param-value>
Content-Type,X-Requested-With,accept,Origin,Access-Control-Request-Method,Access-Control-Request-Headers,Access-Control-Allow-Origin
</param-value>
</init-param>
<init-param>
<param-name>cors.exposed.headers</param-name>
<param-value>
Access-Control-Allow-Origin,Access-Control-Allow-Credentials
</param-value>
</init-param>
<init-param>
<param-name>cors.support.credentials</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>cors.preflight.maxage</param-name>
<param-value>10</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CorsFilter</filter-name>
<url-pattern>/wxrefund/*</url-pattern>
</filter-mapping>
浏览器拒绝HTTP请求的跨域,CORS的背后基本思想就是使用自定义的HTTP头部让浏览器与服务器进行沟通,从而决定请求响应是应该成功还是应该失败。
浏览器直接发出CORS请求(在头信息中增加一个Origin
字段,说明:本次请求来自哪个源)
GET /cors HTTP/1.1
Origin: http://api.bob.com
Host: api.alice.com
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0...
Origin
指定的域名在许可范围内,服务器返回的响应,会多出几个头信息字段。
Access-Control-Allow-Origin: http://api.bob.com
Access-Control-Allow-Credentials: true
Access-Control-Expose-Headers: FooBar
Content-Type: text/html; charset=utf-8
Access-Control-Allow-Origin
Access-Control-Allow-Origin,该字段是必须的。它的值要么是请求时Origin字段的值,要么是一个*,表示接受任意域名的请求。
Access-Control-Allow-Credentials,该字段可选。它的值是一个布尔值,表示是否允许发送Cookie。这个值也只能设为true,如果服务器不要浏览器发送Cookie,删除该字段即可。
Access-Control-Expose-Headers,该字段可选。CORS请求时,XMLHttpRequest对象的getResponseHeader()方法只能拿到6个基本字段:Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma。如果想拿到其他字段,就必须在Access-Control-Expose-Headers里面指定。示例:
客服端(就是JavaScript中)
function getHello() {
var xhr = new XMLHttpRequest();
xhr.open("post", "http://b.example.com/Test.ashx", true);
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
// 声明请求源
xhr.setRequestHeader("Origin", "http://a.example.com");
xhr.onreadystatechange = function () {
if (xhr.readyState == 4 && xhr.status == 200) {
var responseText = xhr.responseText;
console.info(responseText);
}
}
xhr.send();
}
服务器端:
public class Test : IHttpHandler{
public void ProcessRequest(HttpContext context){
context.Response.ContentType = "text/plain";
// 声明接受所有域的请求
context.Response.AddHeader("Access-Control-Allow-Origin", "*");
context.Response.Write("Hello World");
}
public bool IsReusable{
get
{
return false;
}
}
}
有点思路整理下;
我在浏览器(JavaScript)上向一个服务器发送请求,浏览器会拒绝这个请求,怎么解决呢?
首先,JavaScript发送请求时添加头xhr.setRequestHeader("Origin","http://a.example.com");这样浏览器就不会拒绝它;
而服务器回的报头Access-Control-Allow-Origin:*就能与JavaScript相通。