Apache
在D:\project\web\index.html中写入
<h1>welcome useing apache!</h1>
基于ip访问
打开phpstudy_pro\Extensions\Apache2.4.39\conf\extra\httpd-vhosts.conf写入
<VirtualHost 192.168.1.4:80>ServerAdmin 88888888@163.com #管理员邮箱DocumentRoot "D:\project\web" #网站根目录ServerName www.index.com #域名ServerName www.index666.com #网站别名ErrorLog "logs/dummy-host2.example.com-error.log" #错误日志 CustomLog "logs/dummy-host2.example.com-access.log" common #访问日志
</VirtualHost>
基于域名访问
在httpd.conf里取消注释
httpd-vhosts.conf文件内写入
<VirtualHost *:80>#增加站点DocumentRoot "D:\project\web"#增加主机名ServerName "www.index.com"<Directory "D:\project\web">#允许所有请求Require all granted#重写不生效AllowOverride None#不启用任何服务器特性Options None</Directory>
</VirtualHost>
在windows主机的C:\Windows\System32\drivers\etc\hosts文件写入
127.0.0.1 www.index.com
<?php phpinfo();
站点目录写入php文件
基于端口访问
在listen.conf中添加81端口
httpd-vhosts.conf文件内写入
<VirtualHost 192.168.175.128:81>DocumentRoot "D:\project\web"ServerName www.index.com
</VirtualHost>
ngninx
基于端口
vim /etc/nginx/conf.d/server.confserver{listen 81;server_name localhost;location /{root /var/www/nginx/server; #指定网页访问的目录index index.html index.htm; #指定访问的主页}
}
创建网页文件
mkdir -p /var/www/nginx/server
vim /var/www/nginx/server/index.html
nginx -t #检查nginx运行配置是否正确
systemctl restart nginx #重启nginx服务
基于域名
修改windows下的hosts文件这里Windows主机和Linux主机一定要能相互ping通
vim /etc/nginx/conf.d/server.conf server{listen 80;server_name www.ikun.com;location /{root /var/www/nginx/server;index index.html index.htm;}
}
测试时关闭防火墙
systemctl stop firewalld.service
基于ip
添加一个网卡
vim /etc/nginx/conf.d/server.conf server{listen 80;server_name 192.168.150.129;location /{root /var/www/nginx/server;index index.html index.htm;}
}
测试时关闭防火墙
systemctl stop firewalld.service
非简单请求
非简单请求
常见的情况有 Content-Type 为 application/json 的请求。浏览器在发出非简单请求前,会发送一次 options 请求。用于先询问服务器,当前域名是否被允许访问,以及可以使用哪些 methods 和 headers。只有服务器做出肯定的响应,浏览器才会发出正式的请求,否则就会报错。
options 请求的请求头会带上三个头
Origin 当前请求域名,必须
Access-Control-Request-Method 必须,用来列出正式请求的 method,例如 POST
Access-Control-Request-Headers 多个值用逗号隔开,例如 Content-Type
options 响应的响应头
Access-Control-Allow-Origin 必须,和简单请求一样
Access-Control-Allow-Credentials 可选,和简单请求一样
Access-Control-Max-Age 可选,用来指定本次 options 请求的有效期。单位为秒,在有效期内,不用发出另一条预检请求。
Access-Control-Allow-Methods 必须,多个 method 用逗号隔开,表明服务器支持的所有跨域请求的方法。注意,返回的是所有支持的方法,而不单是浏览器请求的方法。这是为了避免多次预检请求。
Access-Control-Allow-Headers 如果浏览器请求头里包括 Access-Control-Request-Headers 字段,则 Access-Control-Allow-Headers 字段是必需的。多个值用逗号隔开,表明服务器支持的所有头信息字段,不限于浏览器在预检中请求的字段
然后返回 http 状态码 204
跨域知识点整理
那就是浏览器的“同源策略”(即协议相同,域名相同,端口相同)。如果非同源,共有三种行为会受到限制:
(1) Cookie,LocalStorage和IndexdDB无法读取
(2) DOM无法获得
(3) AJAX请求不能发送
Cookie
Cookie 是服务器写入浏览器的一小段信息,只有同源的网页才能共享。我们可以在cookie中设置domain的值为一级域名,这样一级域名相同,二级域名不同的网页也可以共享cookie。
iframe
如果两个网页不同源,就无法拿到对方的DOM。对于完全不同源的网站,目前有三种方法,可以解决跨域窗口的通信问题。
- 片段标识符
- window.name
- 跨文档通信API
- 片段标识符
片段标识符(fragment identifier)指的是,URL的#号后面的部分,比如http://example.com/x.html#fragment的#fragment。如果只是改变片段标识符,页面不会重新刷新。
父窗口可以把信息,写入子窗口的片段标识符。
var src = originURL + '#' + data;
document.getElementById('myIFrame').src = src;
子窗口通过监听hashchange事件得到通知。
window.onhashchange = checkMessage;function checkMessage() {var message = window.location.hash;// ...
}
同样的,子窗口也可以改变父窗口的片段标识符。
window.name
浏览器窗口有window.name属性。这个属性最大的特点是,无论是否同源,只要在同一个窗口里,前一个网页设置了这个属性,后一个网页就可以读取它。比如说,一个网页中包含一个iframe,我们把它的window.name设置为我们想访问的内部数据。这样在该网页中就能通过document.getElementById(‘myFrame’).contentWindow.name来访问它了。
这种方法的优点是,window.name容量很大,可以放置非常长的字符串;缺点是必须监听子窗口window.name属性的变化,影响网页性能。
- Window.postMessage
HTML5引入了一个全新的API:跨文档通信API(Cross-document messaging)。这个API为window对象新增了一个window.postMessage方法,允许跨窗口,不论这两个窗口是否同源。这个功能的实现包括接受信息的“message”事件和发送消息的“postMessage”方法。
语法:
otherWindow.postMessage(message, targetOrigin);
otherWindow指目标窗口,也就是给哪个window发消息,是window.frames的成员或者由window.open方法创建的窗口。
参数说明:
message:是要发送的消息,类型为 String、Object (IE8、9 不支持)
targetOrigin: 是限定消息接收范围,不限制请使用 ‘*’
var onmessage = function (event) {var data = event.data;var origin = event.origin;//do someing};if (typeof window.addEventListener != 'undefined') {window.addEventListener('message', onmessage, false);} else if (typeof window.attachEvent != 'undefined') {//for iewindow.attachEvent('onmessage', onmessage);}
回调函数第一个参数接收 Event 对象,有三个常用属性:
data: 消息
origin: 消息来源地址
source: 源 DOMWindow 对象
例一:使用iframe创建子窗口
<!doctype html>
<html lang="en">
<head><meta charset="UTF-8"><title>window.postMessage</title>
</head>
<body>
<iframe src="subFrame.html" id="myFrame" frameborder="0"></iframe><script>
var iframe = document.getElementById('myFrame').contentWindow;
setInterval(function () {iframe.postMessage('Hello', '*');
}, 6000);var onmessage = function (event) {var data = event.data;var origin = event.origin;console.log(data);console.log(origin);};if (typeof window.addEventListener != 'undefined') {window.addEventListener('message', onmessage, false);} else if (typeof window.attachEvent != 'undefined') {//for iewindow.attachEvent('onmessage', onmessage);}
</script>
</body>
</html>
例二:使用window.open打开窗口
<!--父窗口-->
<!doctype html>
<html lang="en">
<head><meta charset="UTF-8"><title>window.postMessage</title>
</head>
<body>
<script>var popup = window.open('subFrame.html');setInterval(function () {popup.postMessage('Hello World', '*');},6000);var onmessage = function (event) {var data = event.data;var origin = event.origin;console.log(data);console.log(origin);};if (typeof window.addEventListener != 'undefined') {window.addEventListener('message', onmessage, false);} else if (typeof window.attachEvent != 'undefined') {//for iewindow.attachEvent('onmessage', onmessage);}
</script>
</body>
</html>
<!--子窗口-->
<!doctype html>
<html lang="en">
<head><title>subFrame</title>
</head>
<body><script>
window.opener.postMessage('nice to see you', '*');var onmessage = function (event) {var data = event.data;var origin = event.origin;console.log(data);console.log(origin);
};
if (typeof window.addEventListener != 'undefined') {window.addEventListener('message', onmessage, false);
} else if (typeof window.attachEvent != 'undefined') {//for iewindow.attachEvent('onmessage', onmessage);
}
</script>
</body>
</html>
通过window.postMessage,读写其他窗口的 LocalStorage 也成为了可能。
AJAX
同源政策规定,AJAX请求只能发给同源的网址,否则就报错。以下四种方法可以规避这个限制:
1.JSONP
2.CORS
3.WebSocket
JSONP
JSONP即JSON with padding,它有两部分组成,回调函数和数据。它的基本思想是,网页通过添加一个
<!DOCTYPE html>
<html>
<head><title>JSONP Example</title>
</head>
<body><script>function handleResponse(response){alert("You're at IP address " + response.ip + ", which is in " + response.city + ", " + response.region_name);}var script = document.createElement("script");script.src = "http://freegeoip.net/json/?callback=handleResponse";document.body.insertBefore(script, document.body.firstChild);</script>
</body>
</html>
CORS
一、简介
CORS需要浏览器和服务器同时支持。目前,所有浏览器都支持该功能,IE浏览器不能低于IE10。
整个CORS通信过程,都是浏览器自动完成,不需要用户参与。对于开发者来说,CORS通信与同源的AJAX通信没有差别,代码完全一样。浏览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。
因此,实现CORS通信的关键是服务器。只要服务器实现了CORS接口,就可以跨源通信。
二、两种请求
浏览器将CORS请求分成两类:简单请求(simple request)和非简单请求(not-so-simple request)。
只要同时满足以下两大条件,就属于简单请求。
(1) 请求方法是以下三种方法之一:HEADGETPOST(2)HTTP的头信息不超出以下几种字段:AcceptAccept-LanguageContent-LanguageLast-Event-IDContent-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain
凡是不同时满足上面两个条件,就属于非简单请求。
浏览器对这两种请求的处理,是不一样的。
三、简单请求
3.1 基本流程
对于简单请求,浏览器直接发出CORS请求。具体来说,就是在头信息之中,增加一个Origin字段。
下面是一个例子,浏览器发现这次跨源AJAX请求是简单请求,就自动在头信息之中,添加一个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字段用来说明,本次请求来自哪个源(协议 + 域名 + 端口)。服务器根据这个值,决定是否同意这次请求。
如果Origin指定的源,不在许可范围内,服务器会返回一个正常的HTTP回应。浏览器发现,这个回应的头信息没有包含Access-Control-Allow-Origin字段(详见下文),就知道出错了,从而抛出一个错误,被XMLHttpRequest的onerror回调函数捕获。注意,这种错误无法通过状态码识别,因为HTTP回应的状态码有可能是200。
如果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
上面的头信息之中,有三个与CORS请求相关的字段,都以Access-Control-开头。
(1)Access-Control-Allow-Origin
该字段是必须的。它的值要么是请求时Origin字段的值,要么是一个*,表示接受任意域名的请求。
(2)Access-Control-Allow-Credentials
该字段可选。它的值是一个布尔值,表示是否允许发送Cookie。默认情况下,Cookie不包括在CORS请求之中。设为true,即表示服务器明确许可,Cookie可以包含在请求中,一起发给服务器。这个值也只能设为true,如果服务器不要浏览器发送Cookie,删除该字段即可。
(3)Access-Control-Expose-Headers
该字段可选。CORS请求时,XMLHttpRequest对象的getResponseHeader()方法只能拿到6个基本字段:Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma。如果想拿到其他字段,就必须在Access-Control-Expose-Headers里面指定。上面的例子指定,getResponseHeader(‘FooBar’)可以返回FooBar字段的值。
3.2 withCredentials 属性
上面说到,CORS请求默认不发送Cookie和HTTP认证信息。如果要把Cookie发到服务器,一方面要服务器同意,指定Access-Control-Allow-Credentials字段。
Access-Control-Allow-Credentials: true
另一方面,开发者必须在AJAX请求中打开withCredentials属性。
var xhr = new XMLHttpRequest();
xhr.withCredentials = true;
否则,即使服务器同意发送Cookie,浏览器也不会发送。或者,服务器要求设置Cookie,浏览器也不会处理。
但是,如果省略withCredentials设置,有的浏览器还是会一起发送Cookie。这时,可以显式关闭withCredentials。
xhr.withCredentials = false;
需要注意的是,如果要发送Cookie,Access-Control-Allow-Origin就不能设为星号,必须指定明确的、与请求网页一致的域名。同时,Cookie依然遵循同源政策,只有用服务器域名设置的Cookie才会上传,其他域名的Cookie并不会上传,且(跨源)原网页代码中的document.cookie也无法读取服务器域名下的Cookie。
WebSocket
WebSocket是一种通信协议,使用ws://(非加密)和wss://(加密)作为协议前缀。该协议不实行同源政策,只要服务器支持,就可以通过它进行跨源通信。
下面是一个例子,浏览器发出的WebSocket请求的头信息。
GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13
Origin: http://example.com
上面代码中,有一个字段是Origin,表示该请求的请求源(origin),即发自哪个域名。
正是因为有了Origin这个字段,所以WebSocket才没有实行同源政策。因为服务器可以根据这个字段,判断是否许可本次通信。如果该域名在白名单内,服务器就会做出如下回应。
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=
Sec-WebSocket-Protocol: chat
发送数据,因为WebScoket只能通过连接发送纯文本数据,所以对于复杂的数据结构在发送之前必须进行序列化。
socket.send(JSON.stringfy(data));
接收数据:
socket.onmessage = function(event){};
关闭连接:
socket.close()