一、关于http的206状态码和416状态码的意义及断点续传
HTTP 2xx范围内的状态码表明客户端发送的请求已经被服务器接受并且被成功处理了,HTTP/1.1 206状态码表示客户端通过发送范围请求头Range抓取到了资源的部分数据,一般用来解决大文件下载问题,一般CDN服务器都会支持这种能力。能否支持206只要看服务端响应头信息中是否存在 accept-ranges: bytes 这种头信息。accept-ranges: bytes表明服务器支持Range请求,以及服务器所支持的单位是字节(这也是唯一可用的单位).Content-Length响应头表明了响应实体的大小,也就是真实的视频等文件的大小,如下即是995664字节。
accept-ranges: bytes
access-control-allow-origin: *
cache-control: max-age=2592000
content-length: 995664
content-md5: Qj7WNfwWVjEqxqjP9Xv1DA==
content-type: application/octet-stream
服务器支持accept-ranges: bytes,即支持断点续传,并且支持同时下载文件的各部分,即下载工具可以利用范围请求加速下载。而Accept-Ranges: none的情况下即表示响应头表示服务器不支持范围请求。对于支持断点续传的服务端,客户端可以使用curl进行简单的测试,比如我们有一张图片:/uploads/pageimg/20200116164037_24480.png 通过请求查看是支持accept-ranges: bytes的,总大小为Content-Length: 5798,我们可以在linux下试验如下:
root@nuser1-24:/opt# curl --header "Range: bytes=0-3000" /uploads/pageimg/20200116164037_24480.png -o part_a
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 3001 100 3001 0 0 10724 0 --:--:-- --:--:-- --:--:-- 10756
root@nuser1-24:/opt# curl --header "Range: bytes=3001-" /uploads/pageimg/20200116164037_24480.png -o part_b
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 2797 100 2797 0 0 18141 0 --:--:-- --:--:-- --:--:-- 18162
root@nuser1-24:/opt# sz part_a
root@nuser1-24:/opt# sz part_b
root@nuser1-24:/opt# cat part_a part_b >> part
root@nuser1-24:/opt# sz part
在下载下来的文件中,part就是一个完整的图片,而part_a图片可以打开(使用windows下的画图软件即可),并且能看到一半的图片,part_b因为没有part_a中的图片头信息无法在windows查看到。
服务端要支持Accept-Ranges bytes也很简单,nginx只需要在配置文件中添加下面这一行即可:
add_header Accept-Ranges bytes;
416状态码是和206状态码相关联的一个状态码,HTTP 416错误代表所请求的范围无法满足 (Requested Range not satisfiable),即请求的range值超过了文件的大小,如下请求设置range为10000以上,而实际文件大小不到6000,就会报416错误:
root@n67:/opt# curl -v --header "Range: bytes=10000-" /uploads/pageimg/20200116164037_24480.png -o part_b
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0* Trying 114.215.80.214...
* Connected to www.007.cn (114.215.80.214) port 80 (#0)
> GET /uploads/pageimg/20200116164037_24480.png HTTP/1.1
> Host: www.007.cn
> User-Agent: curl/7.47.0
> Accept: */*
> Range: bytes=10000-
>
< HTTP/1.1 416 Requested Range Not Satisfiable
< Server: nginx
< Date: Fri, 17 Jan 2020 10:34:30 GMT
< Content-Type: text/html
< Content-Length: 206
< Connection: keep-alive
< Expires: Sun, 16 Feb 2020 10:34:30 GMT
< Cache-Control: max-age=2592000
< Content-Range: bytes */5798
<
{ [206 bytes data]
100 206 100 206 0 0 7045 0 --:--:-- --:--:-- --:--:-- 7103
* Connection #0 to host www.007.cn left intact
二、CORS使用Access-Control-Allow-Origin来允许跨域请求
因为浏览器的同源策略,浏览器只允许请求当前域的资源,而对其他域的资源以不信任的态度处理。JSONP是可以解决跨域的一些问题,但JSONP只支持GET请求而不支持POST,因此还是有限,而使用Access-Control-Allow-Origin可以应对各种跨域请求。
CORS全称跨域资源共享(Cross-origin resource sharing),这是W3C的标准,即是使用Access-Control-Allow-Origin来允许跨域请求,对这种请求也有标准的处理流程。
对于跨域的请求,浏览器端先向目标服务器发送OPTION请求判断请求头中是否存在Access-Control-Allow-Origin头信息,Access-Control-Allow-Origin是允许跨域请求的标志。如果没有,浏览器就会报错No Access-Control-Allow-Origin header is present on the requested resource
Access to XMLHttpRequest at 'https://007.cn/test/cross' from origin 'https://007.com' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
因为此时浏览器向目标服务器发送了OPTION请求并携带access-control-request-method和access-control-request-headers告诉目标服务器它的请求方式和所要发送的头信息,检测目标服务器是否准许,示例如下:
Request Method: OPTIONS
access-control-request-headers: content-type,cookies
access-control-request-method: POST
而如果这个OPTION请求未得到200响应的话,则浏览器不会进行下一步。且会报错It does not have HTTP ok status:
Access to XMLHttpRequest at 'https://007.cn/test/cross' from origin 'https://007.com' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: It does not have HTTP ok status。
即服务器必须在OPTION请求中响应200状态,并且允许使用的headers和method。此时需要对目标服务器的nginx处理添加一些头信息如下,不一定全部都需要。
add_header Access-Control-Allow-Origin "https://007.com'" always;
add_header Access-Control-Allow-Headers "Content-type,Origin,X-Auth-Token,X-JSON,Cookies,Cookie,Content-Length" always;
add_header Access-Control-Allow-Methods "GET,POST,OPTIONS" always;
add_header Access-Control-Allow-Credentials "true" always;
add_header Access-Control-Max-Age "86400" always;
需要注意的是:Access-Control-Allow-Origin 可以设置为*,但是如果设置为*,则跨域请求不会携带cookie,所以如果需要传输cookie,还是需要有目的允许一些跨域来源地址。
Access-Control-Allow-Credentials表示允许携带认证信息(cookies)
Access-Control-Allow-Methods 不必说,可按需要开放哪些请求方式。
Access-Control-Allow-Headers 表示允许的请求头信息。比如如果这个字段中没有Cookie而同时又需要传输cookie的话,就会报下面的错误:
Access to XMLHttpRequest at 'https://007.cn/test/cross' from origin 'https://007.com' has been blocked by CORS policy: Request header field cookies is not allowed by Access-Control-Allow-Headers in preflight response。
这一步的OPTION请求OK的话,浏览器才会正式执行跨域的请求。上面服务端响应头信息的时候,注意看到最后都带了一个always标志。如果服务端修改后仍没有响应所需要的头信息的时候,可以在最后加个always试试,挺好用。