比特派钱包安卓版官网网址链接|cros

作者: 比特派钱包安卓版官网网址链接
2024-03-07 17:58:54

跨域(CORS)产生原因分析与解决方案,这一次彻底搞懂它 - 知乎

跨域(CORS)产生原因分析与解决方案,这一次彻底搞懂它 - 知乎首发于Nodejs技术栈切换模式写文章登录/注册跨域(CORS)产生原因分析与解决方案,这一次彻底搞懂它五月君艺术源于生活而高于生活,编程亦是如此。Cross-origin Resource Sharing 中文名称 “跨域资源共享” 简称 “CORS”,它突破了一个请求在浏览器发出只能在同源的情况下向服务器获取数据的限制。本文会先从一个示例开始,分析是浏览器还是服务器的限制,之后讲解什么时候会产生预检请求,在整个过程中,也会讲解一下解决该问题的实现方法,文末会再总结如何使用 Node.js 中的 cors 模块和 Nginx 反向代理来解决跨域问题。文中使用 Node.js 做一些 Demo 的演示,每一小节之后也会给予代码的 Demo 地址。浏览器还是服务器的限制先思考下,CORS 是浏览器端还是服务器端的限制?为了更好的说明这个问题,从一段示例开始。从一段示例开始index.html创建 index.html 使用 fetch 调用 http://127.0.0.1:3011/api/data

client.js创建 client.js 用来加载上面 index.html。设置端口为 3010。const http = require('http');

const fs = require('fs');

const PORT = 3010;

http.createServer((req, res) => {

fs.createReadStream('index.html').pipe(res);

}).listen(PORT);

server.js创建 server.js 开启一个服务,根据不同的请求返回不同的响应。设置端口为 3011。const http = require('http');

const PORT = 3011;

http.createServer((req, res) => {

const url = req.url;

console.log('request url: ', url);

if (url === '/api/data') {

return res.end('ok!');

}

if (url === '/script') {

return res.end('console.log("hello world!");');

}

}).listen(PORT);

console.log('Server listening on port ', PORT);

测试分析原因运行上面的 client.js、server.js 浏览器输入 http://127.0.0.1:3010 在 Chrome 浏览器中打开 Network 项查看请求信息,如下所示:左侧是使用 fetch 请求的 127.0.0.1:3011/api/data 接口,在请求头里可以看到有 Origin 字段,显示了我们当前的请求信息。另外还有三个 Sec-Fetch-* 开头的字段,这是一个新的草案 Fetch Metadata Request Headers[1]。其中 Sec-Fetch-Mode 表示请求的模式,通过左右两侧结果对比也可以看出左侧是跨域的。Sec-Fetch-Site 表示的是这个请求是同源还是跨域,由于我们这两个请求都是由 3010 端口发出去请求 3011 端口,是不符合同源策略的。看下浏览器 Console 下的日志信息,根据提示得知原因是从 “http://127.0.0.1:3010” 访问 “http://127.0.0.1:3011/api/data” 被 CORS 策略阻止了,没有 “Access-Control-Allow-Origin” 标头。在看下服务端的日志,因为请求 3011 服务,所以就看下 3011 服务的日志信息:Server listening on port 3011

request url: /script

request url: /api/data

在服务端是有收到请求信息的,说明服务端是正常工作的。我们也可以在终端通过 curl 命令测试下,在终端脱离浏览器环境也是可以正常请求的。$ curl http://127.0.0.1:3011/api/data

ok!

本节代码示例:github.com/qufei1993/http-protocol/tree/master/example/cors/01

总结回答最开始提出的问题浏览器限制了从脚本内发起的跨源 HTTP 请求,例如 XMLHttpRequest 和我们本示例中使用的 Fetch API 都是遵循的同源策略。当一个请求在浏览器端发送出去后,服务端是会收到的并且也会处理和响应,只不过浏览器在解析这个请求的响应之后,发现不属于浏览器的同源策略(地址里面的协议、域名和端口号均相同)也没有包含正确的 CORS 响应头,返回结果被浏览器给拦截了。预检请求预检请求是在发送实际的请求之前,客户端会先发送一个 OPTIONS 方法的请求向服务器确认,如果通过之后,浏览器才会发起真正的请求,这样可以避免跨域请求对服务器的用户数据造成影响。看到这里你可能有疑问为什么上面的示例没有预检请求?因为 CORS 将请求分为了两类:简单请求和非简单请求。我们上面的情况属于简单请求,所以也就没有了预检请求。让我们继续在看下简单请求和非简单请求是如何定义的。预检请求定义根据 MDN 的文档定义,请求方法为:GET、POST、HEAD,请求头 Content-Type 为:text/plain、multipart/form-data、application/x-www-form-urlencoded 的就属于 “简单请求” 不会触发 CORS 预检请求。例如,如果请求头的 Content-Type 为 application/json 就会触发 CORS 预检请求,这里也会称为 “非简单请求”。“MDN 文档 http://developer.mozilla.org/en-US/docs/Web/HTTP/CORS 简单请求”[2] 有更多关于简单请求的字段定义。预检请求示例通过一个示例学习下预检请求。设置客户端为 index.html 里的 fetch 方法增加一些设置,设置请求的方法为 PUT,请求头增加一个自定义字段 Test-Cors。

上述代码在浏览器执行时会发现是一个非简单请求,就会先执行一个预检请求,Request Headers 会有如下信息:OPTIONS /api/data HTTP/1.1

Host: 127.0.0.1:3011

Access-Control-Request-Method: PUT

Access-Control-Request-Headers: content-type,test-cors

Origin: http://127.0.0.1:3010

Sec-Fetch-Mode: cors

可以看到有一个 OPTIONS 是预检请求使用的方法,该方法是在 HTTP/1.1 协议中所定义的,还有一个重要的字段 Origin 表示请求来自哪个源,服务端则可以根据这个字段判断是否是合法的请求源,例如 Websocket 中因为没有了同源策略限制,服务端可以根据这个字段来判断。Access-Control-Request-Method 告诉服务器,实际请求将使用 PUT 方法。Access-Control-Request-Headers 告诉服务器,实际请求将使用两个头部字段 content-type,test-cors。这里如果 content-type 指定的为简单请求中的几个值,Access-Control-Request-Headers 在告诉服务器时,实际请求将只有 test-cors 这一个头部字段。设置服务端上面讲解了客户端的设置,同样的要使请求能够正常响应,还需服务端的支持。修改我们的 server.js 重点是设置 Response Headers 代码如下所示:res.writeHead(200, {

'Access-Control-Allow-Origin': 'http://127.0.0.1:3010',

'Access-Control-Allow-Headers': 'Test-CORS, Content-Type',

'Access-Control-Allow-Methods': 'PUT,DELETE',

'Access-Control-Max-Age': 86400

});

为什么是以上配置?首先预检请求时,浏览器给了服务器几个重要的信息 Origin、Method 为 PUT、Headers 为 content-type,test-cors 服务端在收到之后,也要做些设置,给予回应。Access-Control-Allow-Origin 表示 “http://127.0.0.1:3010” 这个请求源是可以访问的,该字段也可以设置为 “*” 表示允许任意跨源请求。Access-Control-Allow-Methods 表示服务器允许客户端使用 PUT、DELETE 方法发起请求,可以一次设置多个,表示服务器所支持的所有跨域方法,而不单是当前请求那个方法,这样好处是为了避免多次预检请求。Access-Control-Allow-Headers 表示服务器允许请求中携带 Test-CORS、Content-Type 字段,也可以设置多个。Access-Control-Max-Age 表示该响应的有效期,单位为秒。在有效时间内,浏览器无须为同一请求再次发起预检请求。还有一点需要注意,该值要小于浏览器自身维护的最大有效时间,否则是无效的。看下增加了预检请求的效果,第一次先发出了 OPTIONS 请求,并且在请求头设置了本次请求的方法和 Headers 信息,服务端在 Response 也做了回应,在 OPTIONS 成功之后,浏览器紧跟着才发起了我们本次需要的真实请求,如图右侧所示 Resquest Method 为 PUT。本节代码示例:github.com/qufei1993/http-protocol/tree/master/example/cors/02

CORS 与认证对于跨域的 XMLHttpRequest 或 Fetch 请求,浏览器是不会发送身份凭证信息的。例如我们要在跨域请求中发送 Cookie 信息,就要做些设置:为了能看到效果,我先自定义了一个 cookie 信息 id=NodejsRoadmap。重点是设置认证字段,本文中 fetch 示例设置 credentials: "include" 如果是 XMLHttpRequest 则设置 withCredentials:"include"

经过以上设置,浏览器发送实际请求时会向服务器发送 Cookies,同时服务器也需要在响应中设置 Access-Control-Allow-Credentials 响应头res.writeHead(200, {

'Access-Control-Allow-Origin': 'http://127.0.0.1:3010',

'Access-Control-Allow-Credentials': true

});

如果服务端不设置浏览器就不会正常响应,会报一个跨域错误,如下所示:Access to fetch at 'http://127.0.0.1:3011/api/data' from origin 'http://127.0.0.1:3010' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: The value of the 'Access-Control-Allow-Credentials' header in the response is '' which must be 'true' when the request's credentials mode is 'include'.

还有一点需要注意,如果我们在请求中设置了 credentials: "include" 服务端就不能设置 Access-Control-Allow-Origin: "*" 只能设置为一个明确的地址。本节代码示例:github.com/qufei1993/http-protocol/tree/master/example/cors/03

解决跨域问题的几种方法通过上面的分析了解跨域产生的原因之后,解决其实并不难,上面的讲解中其实也提供了解决方案,例如在 Node.js 中我们可以设置响应头部字段 Access-Control-Allow-Origin、Access-Control-Expose-Headers、Access-Control-Allow-Methods 等,但是在实际开发中这样设置难免繁琐,下面介绍几种常用的解决方法。使用 CORS 模块在 Node.js 中推荐你使用 cors 模块 http://github.com/expressjs/cors[3]。在我们本节的示例中,一直使用的 Node.js 原生模块来编写我们的示例,在引入 cors 模块后,可以按照如下方式改写:const http = require('http');

const PORT = 3011;

const corsMiddleware = require('cors')({

origin: 'http://127.0.0.1:3010',

methods: 'PUT,DELETE',

allowedHeaders: 'Test-CORS, Content-Type',

maxAge: 1728000,

credentials: true,

});

http.createServer((req, res) => {

const { url, method } = req;

console.log('request url:', url, ', request method:', method);

const nextFn = () => {

if (method === 'PUT' && url === '/api/data') {

return res.end('ok!');

}

return res.end();

}

corsMiddleware(req, res, nextFn);

}).listen(PORT);

cors 在预检请求之后或在预检请求里并选项中设置了 preflightContinue 属性之后才会执行 nextFn 这个函数,如果预检失败就不会执行 nextFn 函数。如果你用的 Express.js 框架,使用起来也很简单,如下所示:const express = require('express')

const cors = require('cors')

const app = express()

app.use(cors());

JSONP浏览器是允许像 link、img、script 标签在路径上加载一些内容进行请求,是允许跨域的,那么 jsonp 的实现原理就是在 script 标签里面加载了一个链接,去访问服务器的某个请求,返回内容。

相比上面 CORS 模块,JSONP 只支持 GET 请求,显然是没有 CORS 模块强大的。Nginx 代理服务器配置跨域使用 Nginx 代理服务器之后,请求不会直接到达我们的 Node.js 服务器端,请求会先经过 Nginx 在设置一些跨域等信息之后再由 Nginx 转发到我们的 Node.js 服务端,所以这个时候我们的 Nginx 服务器去监听的 3011 端口,我们把 Node.js 服务的端口修改为 30011,简单配置如下所示:server {

listen 3011;

server_name localhost;

location / {

if ($request_method = 'OPTIONS') {

add_header 'Access-Control-Allow-Origin' 'http://127.0.0.1:3010';

add_header 'Access-Control-Allow-Methods' 'PUT,DELETE';

add_header 'Access-Control-Allow-Headers' 'Test-CORS, Content-Type';

add_header 'Access-Control-Max-Age' 1728000;

add_header 'Access-Control-Allow-Credentials' 'true';

add_header 'Content-Length' 0;

return 204;

}

add_header 'Access-Control-Allow-Origin' 'http://127.0.0.1:3010';

add_header 'Access-Control-Allow-Credentials' 'true';

proxy_pass http://127.0.0.1:30011;

proxy_set_header Host $host;

}

}本节代码示例:github.com/qufei1993/http-protocol/tree/master/example/cors/04

总结如果你是一个前端开发者,在工作难免会遇到跨域问题,虽然它属于浏览器的同源策略限制,但是要想解决这问题还需浏览器端与服务端的共同支持,希望读到这篇文章的读者能够理解跨域产生的原因,最后给予的几个解决方案,也希望能解决你对于跨域这个问题的困惑。作者简介:五月君,软件设计师,公众号「Nodejs技术栈」作者。参考资料[1] Fetch Metadata Request Headers: https://w3c.github.io/webappsec-fetch-metadata/[2] “MDN 文档 http://developer.mozilla.org/en-US/docs/Web/HTTP/CORS 简单请求”: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS[3] http://github.com/expressjs/cors: https://github.com/expressjs/cors发布于 2020-08-10 21:47跨域HTTP面试问题​赞同 36​​16 条评论​分享​喜欢​收藏​申请转载​文章被以下专栏收录Nodejs技术栈专注于 Node.js 技术

跨源资源共享(CORS) - HTTP | MDN

共享(CORS) - HTTP | MDNSkip to main contentSkip to searchSkip to select languageMDN Web DocsOpen main menuReferencesReferencesOverview / Web TechnologyWeb technology reference for developersHTMLStructure of content on the webCSSCode used to describe document styleJavaScriptGeneral-purpose scripting languageHTTPProtocol for transmitting web resourcesWeb APIsInterfaces for building web applicationsWeb ExtensionsDeveloping extensions for web browsersWeb TechnologyWeb technology reference for developersGuidesGuidesOverview / MDN Learning AreaLearn web developmentMDN Learning AreaLearn web developmentHTMLLearn to structure web content with HTMLCSSLearn to style content using CSSJavaScriptLearn to run scripts in the browserAccessibilityLearn to make the web accessible to allPlusPlusOverviewA customized MDN experienceAI Help (beta)Get real-time assistance and supportUpdatesAll browser compatibility updates at a glanceDocumentationLearn how to use MDN PlusFAQFrequently asked questions about MDN PlusCurriculumNewBlogPlayAI Help BetaSearch MDNClear search inputSearchThemeLog inSign up for freeWeb 开发技术HTTP跨源资源共享(CORS)Article Actions中文 (简体)此页面由社区从英文翻译而来。了解更多并加入 MDN Web Docs 社区。Filter sidebarClear filter inputIn this article什么情况下需要 CORS?功能概述若干访问控制场景HTTP 响应标头字段HTTP 请求标头字段规范浏览器兼容性参见

HTTP

指南:

资源和 URI

标识互联网上的内容

Data URL

MIME 类型介绍

常见的 MIME 类型

选择 www 或非 www 域名?

HTTP 指南

HTTP 基础

HTTP 概述

HTTP 的发展

HTTP 消息

典型的 HTTP 会话

HTTP/1.x 的连接管理

协议升级机制

HTTP 安全

内容安全策略(CSP)

HTTP Strict Transport Security (HSTS)

X-Content-Type-Options

X-Frame-Options

X-XSS-Protection

Mozilla web security guidelines

Mozilla Observatory

HTTP 访问控制(CORS)

HTTP 认证

HTTP 缓存

HTTP 压缩

HTTP 条件请求

HTTP 内容协商

HTTP cookie

HTTP 范围请求

HTTP 重定向

HTTP 规范

权限策略

参考:

HTTP 标头

AcceptAccept-CHAccept-CH-Lifetime

非标准

已弃用

Accept-CharsetAccept-EncodingAccept-LanguageAccept-PatchAccept-PostAccept-RangesAccess-Control-Allow-CredentialsAccess-Control-Allow-HeadersAccess-Control-Allow-MethodsAccess-Control-Allow-OriginAccess-Control-Expose-HeadersAccess-Control-Max-AgeAccess-Control-Request-HeadersAccess-Control-Request-MethodAgeAllowAlt-SvcAlt-UsedAuthorizationCache-ControlClear-Site-DataConnectionContent-DispositionContent-DPR

非标准

已弃用

Content-EncodingContent-LanguageContent-LengthContent-LocationContent-RangeContent-Security-PolicyContent-Security-Policy-Report-OnlyContent-TypeCookieCritical-CH

实验性

Cross-Origin-Embedder-PolicyCross-Origin-Opener-PolicyCross-Origin-Resource-PolicyDateDevice-MemoryDigest

非标准

已弃用

DNT

非标准

已弃用

Downlink

实验性

DPR

非标准

已弃用

Early-Data

实验性

ECT

实验性

ETagExpectExpect-CTExpiresForwardedFromHostIf-MatchIf-Modified-SinceIf-None-MatchIf-RangeIf-Unmodified-SinceKeep-AliveLarge-Allocation

非标准

已弃用

Last-ModifiedLinkLocationMax-ForwardsNEL

实验性

Observe-Browsing-Topics

实验性

非标准

OriginOrigin-Agent-Cluster

实验性

Permissions-PolicyPragma

已弃用

Proxy-AuthenticateProxy-AuthorizationRangeRefererReferrer-PolicyReporting-EndpointsRetry-AfterRTT

实验性

Save-Data

实验性

Sec-Browsing-Topics

实验性

非标准

Sec-CH-Prefers-Color-Scheme

实验性

Sec-CH-Prefers-Reduced-Motion

实验性

Sec-CH-Prefers-Reduced-Transparency

实验性

Sec-CH-UA

实验性

Sec-CH-UA-Arch

实验性

Sec-CH-UA-Bitness

实验性

Sec-CH-UA-Full-Version

已弃用

Sec-CH-UA-Full-Version-List

实验性

Sec-CH-UA-Mobile

实验性

Sec-CH-UA-Model

实验性

Sec-CH-UA-Platform

实验性

Sec-CH-UA-Platform-Version

实验性

Sec-Fetch-DestSec-Fetch-ModeSec-Fetch-SiteSec-Fetch-UserSec-GPC

实验性

非标准

Sec-PurposeSec-WebSocket-AcceptServerServer-TimingService-Worker-Navigation-PreloadSet-CookieSet-Login

实验性

SourceMapStrict-Transport-SecuritySupports-Loading-Mode

实验性

TETiming-Allow-OriginTk

非标准

已弃用

TrailerTransfer-EncodingUpgradeUpgrade-Insecure-RequestsUser-AgentVaryViaViewport-Width

非标准

已弃用

Want-Digest

非标准

已弃用

Warning

已弃用

Width

非标准

已弃用

WWW-AuthenticateX-Content-Type-OptionsX-DNS-Prefetch-Control

非标准

X-Forwarded-For

非标准

X-Forwarded-Host

非标准

X-Forwarded-Proto

非标准

X-Frame-OptionsX-XSS-Protection

非标准

HTTP 请求方法

CONNECTDELETEGETHEADOPTIONSPATCHPOSTPUTTRACE

HTTP 响应状态码

100 Continue101 Switching Protocols102 Processing103 Early Hints200 OK201 Created202 Accepted203 Non-Authoritative Information204 No Content205 Reset Content206 Partial Content207 Multi-Status208 Already Reported226 IM Used300 Multiple Choices301 Moved Permanently302 Found303 See Other304 Not Modified307 Temporary Redirect308 Permanent Redirect400 Bad Request401 Unauthorized402 Payment Required403 Forbidden404 Not Found405 Method Not Allowed406 Not Acceptable407 Proxy Authentication Required408 Request Timeout409 Conflict410 Gone411 Length Required412 Precondition Failed413 Content Too Large414 URI Too Long415 Unsupported Media Type416 Range Not Satisfiable417 Expectation Failed418 I'm a teapot421 Misdirected Request422 Unprocessable Content423 Locked424 Failed Dependency425 Too Early426 Upgrade Required428 Precondition Required429 Too Many Requests431 Request Header Fields Too Large451 Unavailable For Legal Reasons500 Internal Server Error501 Not Implemented502 Bad Gateway503 Service Unavailable504 Gateway Timeout505 HTTP Version Not Supported506 Variant Also Negotiates507 Insufficient Storage508 Loop Detected510 Not Extended511 Network Authentication Required

CSP 指令

CSP source valuesCSP: base-uriCSP: block-all-mixed-content

已弃用

CSP: child-srcCSP: connect-srcCSP: default-srcCSP: fenced-frame-srcCSP: font-srcCSP: form-actionCSP: frame-ancestorsCSP: frame-srcCSP: img-srcCSP: manifest-srcCSP: media-srcCSP: object-srcCSP: plugin-types

非标准

已弃用

CSP: prefetch-src

非标准

已弃用

CSP: referrer

非标准

已弃用

CSP: report-toCSP: report-uri

已弃用

CSP: require-trusted-types-for

实验性

CSP: sandboxCSP: script-srcCSP: script-src-attrCSP: script-src-elemCSP: style-srcCSP: style-src-attrCSP: style-src-elemCSP: trusted-types

实验性

CSP: upgrade-insecure-requestsCSP: worker-src

CORS 错误

Reason: CORS disabledReason: CORS header 'Access-Control-Allow-Origin' does not match 'xyz'Reason: CORS header 'Access-Control-Allow-Origin' missingReason: CORS header 'Origin' cannot be addedReason: CORS preflight channel did not succeedReason: CORS request did not succeedReason: CORS request external redirect not allowedReason: CORS request not HTTPReason: Credential is not supported if the CORS header 'Access-Control-Allow-Origin' is '*'Reason: Did not find method in CORS header 'Access-Control-Allow-Methods'Reason: expected 'true' in CORS header 'Access-Control-Allow-Credentials'Reason: invalid token 'xyz' in CORS header 'Access-Control-Allow-Headers'Reason: invalid token 'xyz' in CORS header 'Access-Control-Allow-Methods'Reason: missing token 'xyz' in CORS header 'Access-Control-Allow-Headers' from CORS preflight channelReason: Multiple CORS header 'Access-Control-Allow-Origin' not allowed

权限策略指令

Permissions-Policy: accelerometer

实验性

Permissions-Policy: ambient-light-sensor

实验性

Permissions-Policy: autoplay

实验性

Permissions-Policy: battery

实验性

Permissions-Policy: browsing-topics

实验性

非标准

Permissions-Policy: cameraPermissions-Policy: display-capturePermissions-Policy: document-domain

实验性

Permissions-Policy: encrypted-media

实验性

Permissions-Policy: execution-while-not-rendered

实验性

Permissions-Policy: execution-while-out-of-viewport

实验性

Permissions-Policy: fullscreenPermissions-Policy: gamepad

实验性

Permissions-Policy: geolocationPermissions-Policy: gyroscope

实验性

Permissions-Policy: hid

实验性

Permissions-Policy: identity-credentials-get

实验性

Permissions-Policy: idle-detection

实验性

Permissions-Policy: local-fonts

实验性

Permissions-Policy: magnetometer

实验性

Permissions-Policy: microphonePermissions-Policy: midi

实验性

Permissions-Policy: otp-credentials

实验性

Permissions-Policy: payment

实验性

Permissions-Policy: picture-in-picture

实验性

Permissions-Policy: publickey-credentials-create

实验性

Permissions-Policy: publickey-credentials-getPermissions-Policy: screen-wake-lockPermissions-Policy: serial

实验性

Permissions-Policy: speaker-selection

实验性

Permissions-Policy: storage-access

实验性

Permissions-Policy: usb

实验性

Permissions-Policy: web-sharePermissions-Policy: window-management

实验性

Permissions-Policy: xr-spatial-tracking

实验性

In this article什么情况下需要 CORS?功能概述若干访问控制场景HTTP 响应标头字段HTTP 请求标头字段规范浏览器兼容性参见跨源资源共享(CORS)跨源资源共享(CORS,或通俗地译为跨域资源共享)是一种基于 HTTP 头的机制,该机制通过允许服务器标示除了它自己以外的其他源(域、协议或端口),使得浏览器允许这些源访问加载自己的资源。跨源资源共享还通过一种机制来检查服务器是否会允许要发送的真实请求,该机制通过浏览器发起一个到服务器托管的跨源资源的“预检”请求。在预检中,浏览器发送的头中标示有 HTTP 方法和真实请求中会用到的头。

跨源 HTTP 请求的一个例子:运行在 https://domain-a.com 的 JavaScript 代码使用 XMLHttpRequest 来发起一个到 https://domain-b.com/data.json 的请求。

出于安全性,浏览器限制脚本内发起的跨源 HTTP 请求。例如,XMLHttpRequest 和 Fetch API 遵循同源策略。这意味着使用这些 API 的 Web 应用程序只能从加载应用程序的同一个域请求 HTTP 资源,除非响应报文包含了正确 CORS 响应头。

CORS 机制允许 Web 应用服务器进行跨源访问控制,从而使跨源数据传输得以安全进行。现代浏览器支持在 API 容器中(例如 XMLHttpRequest 或 Fetch)使用 CORS,以降低跨源 HTTP 请求所带来的风险。什么情况下需要 CORS?这份跨源共享标准允许在下列场景中使用跨站点 HTTP 请求:

前文提到的由 XMLHttpRequest 或 Fetch API 发起的跨源 HTTP 请求。

Web 字体(CSS 中通过 @font-face 使用跨源字体资源),因此,网站就可以发布 TrueType 字体资源,并只允许已授权网站进行跨站调用。

WebGL 贴图。

使用 drawImage() 将图片或视频画面绘制到 canvas。

来自图像的 CSS 图形 (en-US)。

本文概述了跨源资源共享机制及其所涉及的 HTTP 标头。功能概述跨源资源共享标准新增了一组 HTTP 标头字段,允许服务器声明哪些源站通过浏览器有权限访问哪些资源。另外,规范要求,对那些可能对服务器数据产生副作用的 HTTP 请求方法(特别是 GET 以外的 HTTP 请求,或者搭配某些 MIME 类型的 POST 请求),浏览器必须首先使用 OPTIONS 方法发起一个预检请求(preflight request),从而获知服务端是否允许该跨源请求。服务器确认允许之后,才发起实际的 HTTP 请求。在预检请求的返回中,服务器端也可以通知客户端,是否需要携带身份凭证(例如 Cookie 和 HTTP 认证相关数据)。

CORS 请求失败会产生错误,但是为了安全,在 JavaScript 代码层面无法获知到底具体是哪里出了问题。你只能查看浏览器的控制台以得知具体是哪里出现了错误。

接下来的内容将讨论相关场景,并剖析该机制所涉及的 HTTP 标头字段。若干访问控制场景这里,我们使用三个场景来解释跨源资源共享机制的工作原理。这些例子都使用在任意所支持的浏览器上都可以发出跨域请求的 XMLHttpRequest 对象。简单请求某些请求不会触发 CORS 预检请求。在废弃的 CORS 规范中称这样的请求为简单请求,但是目前的 Fetch 规范(CORS 的现行定义规范)中不再使用这个词语。

其动机是,HTML 4.0 中的

元素(早于跨站 XMLHttpRequest 和 fetch)可以向任何来源提交简单请求,所以任何编写服务器的人一定已经在保护跨站请求伪造攻击(CSRF)。在这个假设下,服务器不必选择加入(通过响应预检请求)来接收任何看起来像表单提交的请求,因为 CSRF 的威胁并不比表单提交的威胁差。然而,服务器仍然必须提供 Access-Control-Allow-Origin 的选择,以便与脚本共享响应。

若请求满足所有下述条件,则该请求可视为简单请求:

使用下列方法之一:

GET

HEAD

POST

除了被用户代理自动设置的标头字段(例如 Connection、User-Agent 或其他在 Fetch 规范中定义为禁用标头名称的标头),允许人为设置的字段为 Fetch 规范定义的对 CORS 安全的标头字段集合。该集合为:

Accept

Accept-Language

Content-Language

Content-Type(需要注意额外的限制)

Range(只允许简单的范围标头值 如 bytes=256- 或 bytes=127-255)

Content-Type 标头所指定的媒体类型的值仅限于下列三者之一:

text/plain

multipart/form-data

application/x-www-form-urlencoded

如果请求是使用 XMLHttpRequest 对象发出的,在返回的 XMLHttpRequest.upload 对象属性上没有注册任何事件监听器;也就是说,给定一个 XMLHttpRequest 实例 xhr,没有调用 xhr.upload.addEventListener(),以监听该上传请求。

请求中没有使用 ReadableStream 对象。

备注: WebKit Nightly 和 Safari Technology Preview 为 Accept、Accept-Language 和 Content-Language 标头字段的值添加了额外的限制。如果这些标头字段的值是“非标准”的,WebKit/Safari 就不会将这些请求视为“简单请求”。WebKit/Safari 并没有在文档中列出哪些值是“非标准”的,不过我们可以在这里找到相关讨论:

Require preflight for non-standard CORS-safelisted request headers Accept, Accept-Language, and Content-Language

Allow commas in Accept, Accept-Language, and Content-Language request headers for simple CORS

Switch to a blacklist model for restricted Accept headers in simple CORS requests

其他浏览器并不支持这些额外的限制,因为它们不属于规范的一部分。

比如说,假如站点 https://foo.example 的网页应用想要访问 https://bar.other 的资源。foo.example 的网页中可能包含类似于下面的 JavaScript 代码:

jsconst xhr = new XMLHttpRequest();

const url = "https://bar.other/resources/public-data/";

xhr.open("GET", url);

xhr.onreadystatechange = someHandler;

xhr.send();

此操作实行了客户端和服务器之间的简单交换,使用 CORS 标头字段来处理权限:

以下是浏览器发送给服务器的请求报文:

httpGET /resources/public-data/ HTTP/1.1

Host: bar.other

User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:71.0) Gecko/20100101 Firefox/71.0

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8

Accept-Language: en-us,en;q=0.5

Accept-Encoding: gzip,deflate

Connection: keep-alive

Origin: https://foo.example

请求标头字段 Origin 表明该请求来源于 http://foo.example。

让我们来看看服务器如何响应:

httpHTTP/1.1 200 OK

Date: Mon, 01 Dec 2008 00:23:53 GMT

Server: Apache/2

Access-Control-Allow-Origin: *

Keep-Alive: timeout=2, max=100

Connection: Keep-Alive

Transfer-Encoding: chunked

Content-Type: application/xml

[…XML Data…]

本例中,服务端返回的 Access-Control-Allow-Origin 标头的 Access-Control-Allow-Origin: * 值表明,该资源可以被任意外源访问。

httpAccess-Control-Allow-Origin: *

使用 Origin 和 Access-Control-Allow-Origin 就能完成最简单的访问控制。如果 https://bar.other 的资源持有者想限制他的资源只能通过 https://foo.example 来访问(也就是说,非 https://foo.example 域无法通过跨源访问访问到该资源),他可以这样做:

httpAccess-Control-Allow-Origin: https://foo.example

备注: 当响应的是附带身份凭证的请求时,服务端必须明确 Access-Control-Allow-Origin 的值,而不能使用通配符“*”。

预检请求与简单请求不同,“需预检的请求”要求必须首先使用 OPTIONS 方法发起一个预检请求到服务器,以获知服务器是否允许该实际请求。"预检请求“的使用,可以避免跨域请求对服务器的用户数据产生未预期的影响。

如下是一个需要执行预检请求的 HTTP 请求:

jsconst xhr = new XMLHttpRequest();

xhr.open("POST", "https://bar.other/resources/post-here/");

xhr.setRequestHeader("X-PINGOTHER", "pingpong");

xhr.setRequestHeader("Content-Type", "application/xml");

xhr.onreadystatechange = handler;

xhr.send("Arun");

上面的代码使用 POST 请求发送一个 XML 请求体,该请求包含了一个非标准的 HTTP X-PINGOTHER 请求标头。这样的请求标头并不是 HTTP/1.1 的一部分,但通常对于 web 应用很有用处。另外,该请求的 Content-Type 为 application/xml,且使用了自定义的请求标头,所以该请求需要首先发起“预检请求”。

备注: 如下所述,实际的 POST 请求不会携带 Access-Control-Request-* 标头,它们仅用于 OPTIONS 请求。

下面是服务端和客户端完整的信息交互。首次交互是预检请求/响应:

httpOPTIONS /doc HTTP/1.1

Host: bar.other

User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:71.0) Gecko/20100101 Firefox/71.0

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8

Accept-Language: en-us,en;q=0.5

Accept-Encoding: gzip,deflate

Connection: keep-alive

Origin: https://foo.example

Access-Control-Request-Method: POST

Access-Control-Request-Headers: X-PINGOTHER, Content-Type

HTTP/1.1 204 No Content

Date: Mon, 01 Dec 2008 01:15:39 GMT

Server: Apache/2

Access-Control-Allow-Origin: https://foo.example

Access-Control-Allow-Methods: POST, GET, OPTIONS

Access-Control-Allow-Headers: X-PINGOTHER, Content-Type

Access-Control-Max-Age: 86400

Vary: Accept-Encoding, Origin

Keep-Alive: timeout=2, max=100

Connection: Keep-Alive

从上面的报文中,我们看到,第 1 - 10 行使用 OPTIONS 方法发送了预检请求,浏览器根据上面的 JavaScript 代码片断所使用的请求参数来决定是否需要发送,这样服务器就可以回应是否可以接受用实际的请求参数来发送请求。OPTIONS 是 HTTP/1.1 协议中定义的方法,用于从服务器获取更多信息,是安全的方法。该方法不会对服务器资源产生影响。注意 OPTIONS 预检请求中同时携带了下面两个标头字段:

httpAccess-Control-Request-Method: POST

Access-Control-Request-Headers: X-PINGOTHER, Content-Type

标头字段 Access-Control-Request-Method 告知服务器,实际请求将使用 POST 方法。标头字段 Access-Control-Request-Headers 告知服务器,实际请求将携带两个自定义请求标头字段:X-PINGOTHER 与 Content-Type。服务器据此决定,该实际请求是否被允许。

第 12 - 21 行为预检请求的响应,表明服务器将接受后续的实际请求方法(POST)和请求头(X-PINGOTHER)。重点看第 15 - 18 行:

httpAccess-Control-Allow-Origin: https://foo.example

Access-Control-Allow-Methods: POST, GET, OPTIONS

Access-Control-Allow-Headers: X-PINGOTHER, Content-Type

Access-Control-Max-Age: 86400

服务器的响应携带了 Access-Control-Allow-Origin: https://foo.example,从而限制请求的源域。同时,携带的 Access-Control-Allow-Methods 表明服务器允许客户端使用 POST 和 GET 方法发起请求(与 Allow 响应标头类似,但该标头具有严格的访问控制)。

标头字段 Access-Control-Allow-Headers 表明服务器允许请求中携带字段 X-PINGOTHER 与 Content-Type。与 Access-Control-Allow-Methods 一样,Access-Control-Allow-Headers 的值为逗号分割的列表。

最后,标头字段 Access-Control-Max-Age 给定了该预检请求可供缓存的时间长短,单位为秒,默认值是 5 秒。在有效时间内,浏览器无须为同一请求再次发起预检请求。以上例子中,该响应的有效时间为 86400 秒,也就是 24 小时。请注意,浏览器自身维护了一个最大有效时间,如果该标头字段的值超过了最大有效时间,将不会生效。

预检请求完成之后,发送实际请求:

httpPOST /doc HTTP/1.1

Host: bar.other

User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:71.0) Gecko/20100101 Firefox/71.0

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8

Accept-Language: en-us,en;q=0.5

Accept-Encoding: gzip,deflate

Connection: keep-alive

X-PINGOTHER: pingpong

Content-Type: text/xml; charset=UTF-8

Referer: https://foo.example/examples/preflightInvocation.html

Content-Length: 55

Origin: https://foo.example

Pragma: no-cache

Cache-Control: no-cache

Arun

HTTP/1.1 200 OK

Date: Mon, 01 Dec 2008 01:15:40 GMT

Server: Apache/2

Access-Control-Allow-Origin: https://foo.example

Vary: Accept-Encoding, Origin

Content-Encoding: gzip

Content-Length: 235

Keep-Alive: timeout=2, max=99

Connection: Keep-Alive

Content-Type: text/plain

[Some XML payload]

预检请求与重定向

并不是所有浏览器都支持预检请求的重定向。如果一个预检请求发生了重定向,一部分浏览器将报告错误:

The request was redirected to 'https://example.com/foo', which is disallowed for cross-origin requests that require preflight.

Request requires preflight, which is disallowed to follow cross-origin redirects.

CORS 最初要求浏览器具有该行为,不过在后续的修订中废弃了这一要求。但并非所有浏览器都实现了这一变更,而仍然表现出最初要求的行为。

在浏览器的实现跟上规范之前,有两种方式规避上述报错行为:

在服务端去掉对预检请求的重定向;

将实际请求变成一个简单请求。

如果上面两种方式难以做到,我们仍有其他办法:

发出一个简单请求(使用 Response.url 或 XMLHttpRequest.responseURL)以判断真正的预检请求会返回什么地址。

发出另一个请求(真正的请求),使用在上一步通过 Response.url 或 XMLHttpRequest.responseURL 获得的 URL。

不过,如果请求是由于存在 Authorization 字段而引发了预检请求,则这一方法将无法使用。这种情况只能由服务端进行更改。附带身份凭证的请求

备注: 当发出跨源请求时,第三方 cookie 策略仍将适用。无论如何改变本章节中描述的服务器和客户端的设置,该策略都会强制执行。

XMLHttpRequest 或 Fetch 与 CORS 的一个有趣的特性是,可以基于 HTTP cookies 和 HTTP 认证信息发送身份凭证。一般而言,对于跨源 XMLHttpRequest 或 Fetch 请求,浏览器不会发送身份凭证信息。如果要发送凭证信息,需要设置 XMLHttpRequest 对象的某个特殊标志位,或在构造 Request 对象时设置。

本例中,https://foo.example 的某脚本向 https://bar.other 发起一个 GET 请求,并设置 Cookies。在 foo.example 中可能包含这样的 JavaScript 代码:

jsconst invocation = new XMLHttpRequest();

const url = "https://bar.other/resources/credentialed-content/";

function callOtherDomain() {

if (invocation) {

invocation.open("GET", url, true);

invocation.withCredentials = true;

invocation.onreadystatechange = handler;

invocation.send();

}

}

第 7 行将 XMLHttpRequest 的 withCredentials 标志设置为 true,从而向服务器发送 Cookies。因为这是一个简单 GET 请求,所以浏览器不会对其发起“预检请求”。但是,如果服务器端的响应中未携带 Access-Control-Allow-Credentials: true,浏览器将不会把响应内容返回给请求的发送者。

客户端与服务器端交互示例如下:

httpGET /resources/credentialed-content/ HTTP/1.1

Host: bar.other

User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:71.0) Gecko/20100101 Firefox/71.0

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8

Accept-Language: en-us,en;q=0.5

Accept-Encoding: gzip,deflate

Connection: keep-alive

Referer: https://foo.example/examples/credential.html

Origin: https://foo.example

Cookie: pageAccess=2

HTTP/1.1 200 OK

Date: Mon, 01 Dec 2008 01:34:52 GMT

Server: Apache/2

Access-Control-Allow-Origin: https://foo.example

Access-Control-Allow-Credentials: true

Cache-Control: no-cache

Pragma: no-cache

Set-Cookie: pageAccess=3; expires=Wed, 31-Dec-2008 01:34:53 GMT

Vary: Accept-Encoding, Origin

Content-Encoding: gzip

Content-Length: 106

Keep-Alive: timeout=2, max=100

Connection: Keep-Alive

Content-Type: text/plain

[text/plain payload]

即使第 10 行指定了 Cookie 是属于 https://bar.other 的内容的,但是,如果 https://bar.other 的响应中缺失 Access-Control-Allow-Credentials: true(第 16 行),则响应内容会被忽略,不会提供给 web 内容。

预检请求和凭据

CORS 预检请求不能包含凭据。预检请求的响应必须指定 Access-Control-Allow-Credentials: true 来表明可以携带凭据进行实际的请求。

备注: 一些企业认证服务要求在预检请求时发送 TLS 客户端证书,这违反了 Fetch 的规范。

Firefox 87 允许通过在设置中设定 network.cors_preflight.allow_client_cert 为 true(Firefox bug 1511151)来允许这种不规范的行为。基于 chromium 的浏览器目前总是在 CORS 预检请求中发送 TLS 客户端证书(Chrome bug 775438)。

附带身份凭证的请求与通配符

在响应附带身份凭证的请求时:

服务器不能将 Access-Control-Allow-Origin 的值设为通配符“*”,而应将其设置为特定的域,如:Access-Control-Allow-Origin: https://example.com。

服务器不能将 Access-Control-Allow-Headers 的值设为通配符“*”,而应将其设置为标头名称的列表,如:Access-Control-Allow-Headers: X-PINGOTHER, Content-Type

服务器不能将 Access-Control-Allow-Methods 的值设为通配符“*”,而应将其设置为特定请求方法名称的列表,如:Access-Control-Allow-Methods: POST, GET

对于附带身份凭证的请求(通常是 Cookie),

这是因为请求的标头中携带了 Cookie 信息,如果 Access-Control-Allow-Origin 的值为“*”,请求将会失败。而将 Access-Control-Allow-Origin 的值设置为 https://example.com,则请求将成功执行。

另外,响应标头中也携带了 Set-Cookie 字段,尝试对 Cookie 进行修改。如果操作失败,将会抛出异常。

第三方 cookie

注意在 CORS 响应中设置的 cookie 适用一般性第三方 cookie 策略。在上面的例子中,页面是在 foo.example 加载,但是第 19 行的 cookie 是被 bar.other 发送的,如果用户设置其浏览器拒绝所有第三方 cookie,那么将不会被保存。

请求中的 cookie(第 10 行)也可能在正常的第三方 cookie 策略下被阻止。因此,强制执行的 cookie 策略可能会使本节描述的内容无效(阻止你发出任何携带凭据的请求)。

Cookie 策略受 SameSite 属性控制。HTTP 响应标头字段本节列出了服务器为访问控制请求返回的 HTTP 响应头,这是由跨源资源共享规范定义的。上一小节中,我们已经看到了这些标头字段在实际场景中是如何工作的。Access-Control-Allow-Origin响应标头中可以携带一个 Access-Control-Allow-Origin 字段,其语法如下:

httpAccess-Control-Allow-Origin: | *

Access-Control-Allow-Origin 参数指定了单一的源,告诉浏览器允许该源访问资源。或者,对于不需要携带身份凭证的请求,服务器可以指定该字段的值为通配符“*”,表示允许来自任意源的请求。

例如,为了允许来自 https://mozilla.org 的代码访问资源,你可以指定:

httpAccess-Control-Allow-Origin: https://mozilla.org

Vary: Origin

如果服务端指定了具体的单个源(作为允许列表的一部分,可能会根据请求的来源而动态改变)而非通配符“*”,那么响应标头中的 Vary 字段的值必须包含 Origin。这将告诉客户端:服务器对不同的 Origin 返回不同的内容。Access-Control-Expose-Headers译者注:在跨源访问时,XMLHttpRequest 对象的 getResponseHeader() 方法只能拿到一些最基本的响应头,Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma,如果要访问其他头,则需要服务器设置本响应头。

Access-Control-Expose-Headers 头将指定标头放入允许列表中,供浏览器的 JavaScript 代码(如 getResponseHeader())获取。

httpAccess-Control-Expose-Headers: [, ]*

例如:

httpAccess-Control-Expose-Headers: X-My-Custom-Header, X-Another-Custom-Header

这样浏览器就能够通过 getResponseHeader 访问 X-My-Custom-Header 和 X-Another-Custom-Header 响应头了。Access-Control-Max-AgeAccess-Control-Max-Age 头指定了 preflight 请求的结果能够被缓存多久,请参考本文在前面提到的 preflight 例子。

httpAccess-Control-Max-Age:

delta-seconds 参数表示 preflight 预检请求的结果在多少秒内有效。Access-Control-Allow-CredentialsAccess-Control-Allow-Credentials 头指定了当浏览器的 credentials 设置为 true 时是否允许浏览器读取 response 的内容。当用在对 preflight 预检测请求的响应中时,它指定了实际的请求是否可以使用 credentials。请注意:简单 GET 请求不会被预检;如果对此类请求的响应中不包含该字段,这个响应将被忽略掉,并且浏览器也不会将相应内容返回给网页。

httpAccess-Control-Allow-Credentials: true

上文已经讨论了附带身份凭证的请求。Access-Control-Allow-MethodsAccess-Control-Allow-Methods 标头字段指定了访问资源时允许使用的请求方法,用于预检请求的响应。其指明了实际请求所允许使用的 HTTP 方法。

httpAccess-Control-Allow-Methods: [, ]*

有关预检请求的示例已在上方给出,包含了将此请求头发送至浏览器的示例。Access-Control-Allow-HeadersAccess-Control-Allow-Headers 标头字段用于预检请求的响应。其指明了实际请求中允许携带的标头字段。这个标头是服务器端对浏览器端 Access-Control-Request-Headers 标头的响应。

httpAccess-Control-Allow-Headers: [, ]*

HTTP 请求标头字段本节列出了可用于发起跨源请求的标头字段。请注意,这些标头字段无须手动设置。当开发者使用 XMLHttpRequest 对象发起跨源请求时,它们已经被设置就绪。OriginOrigin 标头字段表明预检请求或实际跨源请求的源站。

httpOrigin:

origin 参数的值为源站 URL。它不包含任何路径信息,只是服务器名称。

备注: origin 的值可以为 null。

注意,在所有访问控制请求中,Origin 标头字段总是被发送。Access-Control-Request-MethodAccess-Control-Request-Method 标头字段用于预检请求。其作用是,将实际请求所使用的 HTTP 方法告诉服务器。

httpAccess-Control-Request-Method:

相关示例见这里。Access-Control-Request-HeadersAccess-Control-Request-Headers 标头字段用于预检请求。其作用是,将实际请求所携带的标头字段(通过 setRequestHeader() 等设置的)告诉服务器。这个浏览器端标头将由互补的服务器端标头 Access-Control-Allow-Headers 回答。

httpAccess-Control-Request-Headers: [, ]*

相关示例见这里。规范SpecificationFetch Standard # http-access-control-allow-origin浏览器兼容性BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.参见

CORS 错误

启用 CORS:如何在服务器中添加 CORS 支持

XMLHttpRequest

Fetch API

它会 CORS 吗?——交互的 CORS 解释器和生成器

如何不带 CORS 的运行 Chrome 浏览器

在所有(现代)浏览器中使用 CORS

Stack Overflow 面对常见问题的解答:

如何避免 CORS 预检请求

如何利用 CORS 代理避免“No Access-Control-Allow-Origin header”

如何修复“Access-Control-Allow-Origin header must not be the wildcard”

Help improve MDNWas this page helpful to you?YesNoLearn how to contribute.This page was last modified on 2023年10月5日 by MDN contributors.View this page on GitHub• Report a problem with this contentMDN logoYour blueprint for a better internet.MDN on MastodonMDN on X (formerly Twitter)MDN on GitHubMDN Blog RSS FeedMDNAboutBlogCareersAdvertise with usSupportProduct helpReport an issueOur communitiesMDN CommunityMDN ForumMDN ChatDevelopersWeb TechnologiesLearn Web DevelopmentMDN PlusHacks BlogMozilla logoWebsite Privacy NoticeCookiesLegalCommunity Participation GuidelinesVisit Mozilla Corporation’s not-for-profit parent, the Mozilla Foundation.Portions of this content are ©1998–2024 by individual mozilla.org contributors. Content available under a Creative Commons licen

CROS解决跨域 - 掘金

CROS解决跨域 - 掘金

首页 首页

沸点

课程

直播

活动

竞赛

商城

APP

插件 搜索历史

清空

创作者中心

写文章 发沸点 写笔记 写代码 草稿箱 创作灵感

查看更多

会员

登录

注册

CROS解决跨域

未央几许

2019-12-31

1,279

CROS解决跨域

CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing)。

它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。

一、简介

ORS需要浏览器和服务器同时支持。目前,所有浏览器都支持该功能,IE浏览器不能低于IE10。IE 8 和 9 需要通过 XDomainRequest 来实现。

整个CORS通信过程,都是浏览器自动完成,不需要用户参与。对于开发者来说,CORS通信与同源的AJAX通信没有差别,代码完全一样。浏览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。

因此,实现CORS通信的关键是服务器。只要服务器实现了CORS接口,就可以跨源通信。

二、两种请求

浏览器将CORS请求分成两类:简单请求(simple request)和非简单请求(not-so-simple request)。

只要同时满足以下两大条件,就属于简单请求。

(1) 请求方法是以下三种方法之一:

HEAD

GET

POST

(2)HTTP的头信息不超出以下几种字段:

Accept

Accept-Language

Content-Language

Last-Event-ID

Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain

请求中的任意 XMLHttpRequestUpload 对象均没有注册任何事件监听器; XMLHttpRequestUpload 对象可以使用 XMLHttpRequest.upload 属性访问。

三、简单请求

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。

四、非简单请求

4.1 预检请求

非简单请求是那种对服务器有特殊要求的请求,比如请求方法是PUT或DELETE,或者Content-Type字段的类型是application/json。

非简单请求的CORS请求,会在正式通信之前,增加一次HTTP查询请求,称为"预检"请求(preflight)。

浏览器先询问服务器,当前网页所在的域名是否在服务器的许可名单之中,以及可以使用哪些HTTP动词和头信息字段。只有得到肯定答复,浏览器才会发出正式的XMLHttpRequest请求,否则就报错。

下面是一段浏览器的JavaScript脚本。

var url = 'http://api.alice.com/cors';

var xhr = new XMLHttpRequest();

xhr.open('PUT', url, true);

xhr.setRequestHeader('X-Custom-Header', 'value');

xhr.send();

上面代码中,HTTP请求的方法是PUT,并且发送一个自定义头信息X-Custom-Header。

浏览器发现,这是一个非简单请求,就自动发出一个"预检"请求,要求服务器确认可以这样请求。下面是这个"预检"请求的HTTP头信息。

OPTIONS /cors HTTP/1.1

Origin: http://api.bob.com

Access-Control-Request-Method: PUT

Access-Control-Request-Headers: X-Custom-Header

Host: api.alice.com

Accept-Language: en-US

Connection: keep-alive

User-Agent: Mozilla/5.0...

"预检"请求用的请求方法是OPTIONS,表示这个请求是用来询问的。头信息里面,关键字段是Origin,表示请求来自哪个源。

除了Origin字段,"预检"请求的头信息包括两个特殊字段。

(1)Access-Control-Request-Method

该字段是必须的,用来列出浏览器的CORS请求会用到哪些HTTP方法,上例是PUT。

(2)Access-Control-Request-Headers

该字段是一个逗号分隔的字符串,指定浏览器CORS请求会额外发送的头信息字段,上例是X-Custom-Header。

4.2 预检请求的回应

服务器收到"预检"请求以后,检查了Origin、Access-Control-Request-Method和Access-Control-Request-Headers字段以后,确认允许跨源请求,就可以做出回应。

HTTP/1.1 200 OK

Date: Mon, 01 Dec 2008 01:15:39 GMT

Server: Apache/2.0.61 (Unix)

Access-Control-Allow-Origin: http://api.bob.com

Access-Control-Allow-Methods: GET, POST, PUT

Access-Control-Allow-Headers: X-Custom-Header

Content-Type: text/html; charset=utf-8

Content-Encoding: gzip

Content-Length: 0

Keep-Alive: timeout=2, max=100

Connection: Keep-Alive

Content-Type: text/plain

上面的HTTP回应中,关键的是Access-Control-Allow-Origin字段,表示http://api.bob.com可以请求数据。该字段也可以设为星号,表示同意任意跨源请求。

Access-Control-Allow-Origin:

如果浏览器否定了"预检"请求,会返回一个正常的HTTP回应,但是没有任何CORS相关的头信息字段。这时,浏览器就会认定,服务器不同意预检请求,因此触发一个错误,被XMLHttpRequest对象的onerror回调函数捕获。控制台会打印出如下的报错信息。

XMLHttpRequest cannot load http://api.alice.com.

Origin http://api.bob.com is not allowed by Access-Control-Allow-Origin.

服务器回应的其他CORS相关字段如下。

Access-Control-Allow-Methods: GET, POST, PUT

Access-Control-Allow-Headers: X-Custom-Header

Access-Control-Allow-Credentials: true

Access-Control-Max-Age: 1728000

(1)Access-Control-Allow-Methods

该字段必需,它的值是逗号分隔的一个字符串,表明服务器支持的所有跨域请求的方法。注意,返回的是所有支持的方法,而不单是浏览器请求的那个方法。这是为了避免多次"预检"请求。

(2)Access-Control-Allow-Headers

如果浏览器请求包括Access-Control-Request-Headers字段,则Access-Control-Allow-Headers字段是必需的。它也是一个逗号分隔的字符串,表明服务器支持的所有头信息字段,不限于浏览器在"预检"中请求的字段。

(3)Access-Control-Allow-Credentials

该字段与简单请求时的含义相同。

(4)Access-Control-Max-Age

该字段可选,用来指定本次预检请求的有效期,单位为秒。上面结果中,有效期是20天(1728000秒),即允许缓存该条回应1728000秒(即20天),在此期间,不用发出另一条预检请求。

4.3 浏览器的正常请求和回应

一旦服务器通过了"预检"请求,以后每次浏览器正常的CORS请求,就都跟简单请求一样,会有一个Origin头信息字段。服务器的回应,也都会有一个Access-Control-Allow-Origin头信息字段。

下面是"预检"请求之后,浏览器的正常CORS请求。

PUT /cors HTTP/1.1

Origin: http://api.bob.com

Host: api.alice.com

X-Custom-Header: value

Accept-Language: en-US

Connection: keep-alive

User-Agent: Mozilla/5.0...

上面头信息的Origin字段是浏览器自动添加的。

下面是服务器正常的回应。

Access-Control-Allow-Origin: http://api.bob.com

Content-Type: text/html; charset=utf-8

上面头信息中,Access-Control-Allow-Origin字段是每次回应都必定包含的。

参考:www.ruanyifeng.com/blog/2016/0…

未央几许

12

文章

5.3k

阅读

1

粉丝 目录 收起

CROS解决跨域

一、简介

二、两种请求

三、简单请求

3.1 基本流程

3.2 withCredentials 属性

四、非简单请求

4.1 预检请求

4.2 预检请求的回应

4.3 浏览器的正常请求和回应

数字长城的自研引擎,腾讯游戏CROS团队选择了这样一条路_腾讯新闻

数字长城的自研引擎,腾讯游戏CROS团队选择了这样一条路_腾讯新闻

数字长城的自研引擎,腾讯游戏CROS团队选择了这样一条路

腾讯新一代自研引擎全球首曝

“Ten!Nine!Eight!……Three!Two!One!”在工作人员的带领下,全场参会者们一同倒数,宣告着GDC展会正式开展。我跟着大家一起喊,感觉好久没做过如此有仪式感的动作了。

时隔四年,GDC2023终于又回到了旧金山的Moscone中心,来自全球各地的游戏人们齐聚一堂。

我还记得第一天展会结束时,大家聚集在Moscone门外的草地上侃侃而谈,分享着做游戏的趣事或是心得。远处有几棵树刚刚抽出新芽,也有一棵不知道是桃花还是樱花的树,已然挂满枝头。

那一刻,我决定记录下这个画面,不需要什么原因,就只是想做而已。

在旧金山“爬”长城

和安静的演讲会场不同,GDC展会和我们所熟知的游戏展一般热烈。进入现场首先映入眼帘的就是Meta的展台,Quest依旧是Meta的主推对象。正门的左手边是Epic Games,右边wemix,紧贴着Meta还能看到中国的UGC厂商Yahaha,而坐落在展会中央的大多是PlayStation这样的知名游戏公司。

会场内有很多记者拿着长枪短炮对准参会者。当我下电梯后,顺势也当起了摄影师,再次拍下GDC这热闹的瞬间。

游戏人们的热情相同,当然GDC也有一些独特的地方。在GDC现场能看到许多大学的开发社群分享、介绍他们开发游戏的进展,这和ChinaJoy、科隆这样的游戏展还是不太一样的。

展会也设置了不同国家的展馆,包括德国、瑞典、巴西、法国等等。正当我想着会不会有中国馆时,突然我就看到一个熟悉身影“Tencent”图标。那一刻,多少有点见到老乡的感觉(笑)。

今年中国游戏没少在GDC上亮相,比如《王者荣耀》、比如《永劫无间》等。腾讯展馆也被围得水泄不通,排了好久的队,我才体验到,纵观整个GDC现场,最特别的一个展——云游“数字长城”。为啥说特别,因为这是首个国产自研游戏引擎,在文保领域的跨界应用。

临上飞机来美国前,我刚好看到有报道称英国政府将增加游戏公司税务减免,从而支持游戏行业发展。英国的动作也不是一个孤例,过去一年里,俄罗斯、沙特、澳大利亚、欧洲等密集推出政策支持游戏行业发展。

不光如此,游戏产业的重要性,从最近爆火的ChatGPT上就能看到。在GDC2023举办同时,英伟达也举办了GTC大会,并且发布了专为ChatGPT设计的GPU——H100 NVL。

英伟达如今能成为人工智能领域的龙头企业,和游戏是分不开的。这家以游戏显卡发家的公司,依靠着游戏产业的强大消费力和订单量,才能在早期有资本投入到人工智能领域,并持续地扩大市场占有率。

换句话说,游戏和当前大国竞争最激烈的芯片、人工智能等领域息息相关。

同时,作为最前沿、最具创新力和互动性的文化创意产业,游戏的交互性是其他任何一种媒介都难以比拟的,它所带来的沉浸感和文化影响力也是如此。

也正因为如此,自研的游戏引擎,在当前的国际环境下,其意义显得尤为重要。

学其上者,得其中,学其中者,得其下

其实早在去年6月份,“云游长城”小程序就已推出,而这次GDC展出的是用腾讯游戏CROS自研引擎打造的全新版。这是我第一次在线下用键盘鼠标玩,高清晰度下欣赏数字长城,细节颗粒感拉满。

“数字长城”给我的震撼不仅是因为它把许多前沿技术运用在了这个项目里,还因为我能在云游长城的过程里感受到属于我们自己的文化气息。这也让我开始重新审视“数字长城”及其背后游戏技术的意义。

腾讯游戏CROS引擎总监Carter告诉我:“长城是我们中华民族的图腾,肯定是希望更多地考虑用我们自己的自研引擎技术来做,这是一个非常合理的诉求。”做这种超大规模的真实数字场景,对一个全国产自研引擎来说,既是挑战,也是机会。

数字长城自研引擎版项目经理Shun说:“尤其是在渲染效果方面,始终达不到美术的要求标准,团队一时间也找不到方向,经过多次尝试,调整技术和美术方案,提高引擎技术和验收标准,‘学其上者,得其中,学其中者,得其下’,我们逐渐取得进展。”

“我们针对每个技术项都做深入的技术打磨,每个画面甚至每个像素都要保证算法和效果的正确性。通过无数次画面对比的盲测,反复优化,在很多技术专家、美术专家的建议后,终于到达了很不错的渲染效果。”他补充道。

更轻量化、可定制的自研引擎

在现场,腾讯游戏CROS基础研究二组负责人Wingo告诉我,CROS自研引擎专注于大规模渲染、写实的视觉效果和数字内容的在线和离线生成。这些技术正是迎合了未来3A游戏、数字孪生、虚拟现实等应用方向。“数字长城”正是它技术实力的一次生动展现。

同时,得益于“数字长城”等项目挖掘出的GPU能力,腾讯游戏CROS自研引擎在大规模、高精度渲染技术方面积累了更多经验。像“数字长城”项目,长城本体模型就达到了10亿面,贴图量大概是80-90个G。

经过自研引擎技术的优化,这样巨大的资源量可以在普通的PC显卡上顺畅运行。为了能触达移动端用户,腾讯游戏CROS团队将其放到云端上,这也让自研引擎积累了完整的云渲染能力。除此以外,自研引擎还开发了完全实时的全局光照以及大世界动态阴影技术,从而让“数字长城”更加逼真。

腾讯游戏CROS基础研究一组负责人Hanzo表示:“除了前面所说的,腾讯游戏CROS自研引擎相对也更轻量化和可定制化。我们的引擎从设计之初就考虑了模块化,因此定制能力更强也更简单,也有利于我们把引擎应用到更面向未来的方向和游戏之外的工业化领域。”

将自研引擎带入大规模超级数字场景

“数字长城”项目对腾讯和其技术研发团队有着特殊的意义。

Hanzo说:“在这期间我们不但要克服高质量的渲染效果的问题,还要不断边开发边完善引擎的各个系统模块,比如海量光源、底层技术等,还有很多能力也是在项目中得到进一步提升,所以在这个项目里,我们不断完善、优化、验证强化了引擎的核心能力。”

他补充说道,这个项目确实花了很多精力,但很有成就感。

做引擎不是闭门造车,有很多能力和积累都是在项目的需求中反推和倒逼出来的。像“数字长城”这类大规模项目对整个引擎的基础能力和PCG程序化生成、云游戏等自研技术也进行了一个比较好的验证。

跳脱出理性和技术,Carter告诉我,让更多的人可以更便捷地了解长城,是这个项目的初衷。他说道: “其实我们做这个项目之前也没想这么多,一开始就是觉得我们国家大好河山,有很多人看不到真的太可惜了,像我爸妈这么大岁数肯定是爬不上长城了,所以我们能让更多人更安全地了解长城感觉还是很有意义的。”

“那未来呢?”我问,“这毕竟是一个全新的自研引擎,我很想知道未来它会被怎么使用。”

Hanzo也表示,首先还是要承认和世界顶尖技术有差距,未来团队也会在游戏和数字文保这类实践中不断探索和创新。

“之后我们会希望把包括自研引擎在内的技术应用到游戏以外的领域,在工业等大规模的场景进行拓展。我们引擎的轻量化、模块化的特点也更容易适应不同领域的引擎定制需求,”Carter说道,“这样也能在更多领域体现游戏科技的价值。”

“对,工业生产,虚拟模拟,城市重建,这都是有可能的。”Shun补充说。

和我在这届GDC的感受一样,如今的游戏科技,正在不断地外溢到社会其他的领域,影响着其他行业。

长城是不可移动文物,它在物理的世界里消失是必然的。所以不管是从历史的传承来讲,还是用户感受层面来讲,游戏技术都是提供了一种新的方式,可以让这样的文化遗产永续地留在数字世界中。

这是科技的力量,也是游戏的魅力。技术不止于技术,游戏也不止于游戏。

我想,“赛博”和文化遗产于长城上交汇,也是未来和历史在当下的一次握手吧。

腾讯游戏首度揭秘CROS体系:全球精品手游背后的研运秘诀 – 游戏葡萄

腾讯游戏首度揭秘CROS体系:全球精品手游背后的研运秘诀 – 游戏葡萄

Toggle navigation

文章

全部

资讯

深度

海外

专访

专题

寻求报道

我要投稿

搜索

登 录

注 册

资讯

腾讯游戏首度揭秘CROS体系:全球精品手游背后的研运秘诀

文/

菲斯喵

2019-03-27 10:42:15

在GDC2019年度游戏开发者大会期间,腾讯是少数几家将公共研发技术呈现于国际舞台的中国游戏公司。腾讯游戏公共研发运营体系CROS(Common R&D and Operation System)在本次GDC大会上首次公开亮相。北京时间3月21日,腾讯游戏CROS公共研发运营体系在GDC举办了演讲。从演讲内容得知,CROS是专为游戏的研发、运营提供一体化技术支持的服务体系,包含研发效能、品质管理、技术运营、增值服务、游戏安全、用户平台等多项领域的创新技术和产品。而此次GDC上,腾讯游戏CROS着重介绍了四大技术方案:提供一站式自动化测试服务的WeTest、高效一体化的游戏开发框架G6、维护游戏公平竞技环境的安全解决方案MTP、提供专业电竞网优方案的智营网优INO。一直保持低调的腾讯游戏CROS,已支持了国内外200多款精品手游,包括腾讯游戏在海外发行的王者荣耀国际版《AoV》,在CROS专业化、系统化的技术支持下,实现了高效发行和稳健运营。在海外市场,腾讯游戏CROS也已展现出了它在行业中的影响力。去年,腾讯游戏加入了FPA(Fair Play Alliance,公平竞技联盟)——包括Roit Games、Activision Blizzard、Epic Games等一线厂商均是该联盟的成员,由CROS体系下的MTP团队专攻手游安全解决方案、促进游戏竞技生态的良性发展。在今年的GDC 峰会上,MTP的技术专家也为全球开发者们带来了关于反欺诈的主题演讲,揭秘了腾讯游戏在维护公平竞技领域的创新技术应用。另外,CROS体系下的WeTest技术专家,本次受英特尔公司的邀请,在GDC会上分享了Android云游戏技术解决方案。无论是公平竞技还是云游戏服务,都是当下游戏行业的技术动向和关注焦点。在这两大业务上,腾讯游戏CROS与国际大厂的合作,一方面说明了其在游戏安全和云游戏方面的技术实力,另一方面也是腾讯游戏技术输出能力的展现。腾讯游戏CROS的四大技术方案 解决手游研运难题腾讯游戏将内部研发及运营过程中的多项流程、技术、产品进行系统性的梳理和整合,成立了公共研发运营技术体系CROS,集中技术优势助力产品实现更好的品质和体验。本次GDC介绍的WeTest、智营网优INO、MTP、G6四大技术方案,分别为开发者提供了自动化测试、电竞网络优化、游戏安全服务、以及高效开发四个维度的创新技术服务。WeTest:一站式游戏测试和质量开放平台WeTest为游戏提供一站式的测试服务,从业务的布局阶段开始切入,包括立项、研发、上线,并持续到游戏运营的全部周期,帮助开发者实现对游戏高品质的追求。除传统的兼容测试、性能测试、服务器压测、与安全测试外,WeTest持续引入了云测试、云游戏、AI自动化测试、性能大数据分析、舆情大数据分析、舆情预警等新技术,为开发者提供高效的游戏品质服务方案。“测试效率高”、“服务覆盖面全”是WeTest的优势所在。据悉,WeTest云测试服务实现了Top 300机型24小时内的交付能力,轻松覆盖国内90%以上市场;在引入AI测试后,测试效率和成本分别提升100%和节省70%,能够满足大型多人对战、人机交互、音频同步等各类复杂需求;安全服务中,SR渗透测试为包括《王者荣耀》、《QQ飞车手游》在内的300多款游戏提供漏洞挖掘服务,在游戏发布前最大化地降低漏洞风险,保障游戏安全质量;H5小游戏测试解决方案的落地,极大地缩减了首屏加载时间,让用户流失比例降低50%;另外在压力测试中,为开发者提供大师录制回放模式,可以实现自动生成协议填充代码回放,节省80%代码量。智营网优INO:专注游戏网络质量优化智营网优INO(Intelligent Network Optimization,INO)是腾讯游戏CROS在技术运营领域的专业解决方案。该技术方案源于移动电竞赛事中的高质量网络需求,依托于CROS丰富的游戏生态资源,智营网优提供的网络优化技术被广泛应用于全球热门电竞赛事中,通过一站式的网络优化和传输保障服务,成为保障移动电竞赛事体验的核心力量。基于丰富的电竞网络实践和优化经验,智营网优的亮点技术,如4G空口加速、WiFi/4G双链路融合、卡顿诊断等功能,已经被应用到腾讯游戏及行业多款重量级的实时游戏内。智营网优提供的一站式专业移动电竞网络解决方案,通过充分利用有线、4G、WiFi不同特性,根据赛事网络需求定制双通道方案,让游戏数据包同时在内网多链路传输,将赛事的平均延迟降低了90%以上,让网络的稳定可用性达到99.999%,满足移动电竞赛事需求。同时,“实时监控+时之波动”的辅助裁判方案,则更好地保障了赛事的公平性。任何由于网络抖动导致的选手体验受损,可在第一时间自动反馈、告警通知,以协助裁判进行有效裁定。而在极端情况下,“时之波动”功能能够让赛程回到体验受损前任意指定时间,避免重新开局,全面护航电竞赛事稳定公平进行。智营网优INO示意图随着移动电竞在游戏产业和竞技体育中的地位愈加重要,腾讯提出的“实时游戏高优先级、双通道”方案以及需求也获得了业界的认可。同时腾讯游戏的标准专家也在Wi-Fi标准组织中积极推进网络优化方案。IEEE802.11工作组(电气和电子工程师协会IEEE,全称是Institute of Electrical and Electronics Engineers),已经把腾讯提出的实时游戏“低延迟、高稳定”特性正式纳入下一代WiFi标准的工作范畴。MTP:恶意外挂的狙击者恶意外挂是竞技类游戏的天敌。在近些年中,手游的安全问题已越来越复杂,热门的竞技游戏则更容易受到作弊工具的侵扰,公平竞技也已经成为玩家普遍诉求。当游戏的竞技环境被破坏,玩家体验、产品口碑均会受到负面影响。面对日益复杂的手游竞技环境,腾讯游戏CROS的MTP(Mobile Tencent Protect),为开发者提供了一站式移动游戏安全解决方案,从游戏上线前的安全评审、漏洞挖掘、安全加固,到上线后的修改器对抗、变速器对抗和模拟器对抗,再到打金工作室监控与渠道反作弊保护,真正做到覆盖全部游戏周期的安全保护。MTP服务包括了修改器闪退、变速器闪退、虚拟机闪退以及二选一这四大核心功能,针对内存修改,速度修改,虚拟机外挂App和GameGuardian等多种形式的作弊,可以实现即时发现与闪退。另外,MTP服务引入了AI检测技术,可以识别外挂变种,精细化防作弊策略,避免误判。目前,MTP已为数百款游戏提供了反作弊、防破解等游戏安全解决方案,包括《王者荣耀》、《穿越火线:枪战王者》、《QQ飞车手游》、《我叫MT4》等;同时MTP团队与全球一线游戏厂商达成合作,服务超过10亿游戏玩家。随着腾讯游戏加入FPA联盟,MTP作为游戏安全技术服务领域的一支力量,与Roit Games、Activision Blizzard、Epic Games等多个国际大厂联合,共同维护全球游戏公平竞技环境、促进游戏竞技生态的良性发展。G6:为创意游戏提供快速开发支持G6是腾讯游戏CROS的快速开发平台,其一体化的开发框架能够实现快速开发高品质的游戏,满足开发者对于“创意的快速实现”、“产品的迭代效率”等痛点需求。该平台具有游戏客户端、服务器端一体化的特性,包含了一系列简化流程、提高效率的工具,涉及服务器的集群维护,部署等工作。除此之外,G6本身的服务还囊括了游戏语音服务(GVoice)、分布式的数据存储系统、以及下载更新服务等。G6快速开发平台的整体架构其中,GVoice语音服务支持实时语音、语音消息、语音转文字等多种模式,服务对象包括《王者荣耀》、《穿越火线》、《御龙在天》等多款腾讯手游。该语音服务更是以全球连通率99.8%的成绩,得到Netmarble的天堂2,Nexon的DNF,Riot的LOL中国服等多款全球游戏的认可,进而覆盖了100多个国家超过3亿的用户。分布式数据存储系统服务Tcaplus,是G6所拥有的另一大技术亮点。该服务可承载超过3300万同时在线玩家的高性能数据读写,其每秒的存储请求超过2000万/秒,而在此情景下,Tcaplus最终实现低于3毫秒的延迟。这项高性能服务也帮助了《AoV》这款千万级DAU游戏,实现了7x24小时不间断的全球用户数据存储。腾讯游戏CROS 用技术推动数字娱乐发展复杂的全球互联网环境、多样化的用户需求,为数字娱乐行业的发展带来了许多挑战。腾讯游戏的优势不仅在于技术实力,其固有的大平台资源优势,也能够为CROS的服务创造更多更直接的应用场景。比如定制化开发、大数据用户分析、流量上的支持、全球发行接口以及从支付到结算的一站式服务等等。GDC2019现场,CROS团队公开演讲由此看来,将领先的技术实力与其生态资源进行整合,并构筑多维度、链式的开发者服务,或许称得上是腾讯游戏CROS在技术服务领域最大的竞争力体现。腾讯游戏CROS首度亮相并分享了四大技术方案,其目标也正是希望用技术驱动数字娱乐行业的发展。

目录

腾讯游戏

CROS

研发

菲斯喵

这个神秘的家伙没有介绍自己...

相关文章

发表评论

Alex Matveev

2022-06-06 16:27:13

不合规

审核中

@苏某某: 她在音乐方面的喜好,以及对天文的兴趣,也源于这部动画的影响。一直很喜欢爵士乐的她突然开始想

乐方面的喜好,以及对天文的兴趣,也源于这部动画的影响。一直很喜欢爵士乐的她突然开始想,没有系统了解过此类音乐的她怎么会喜欢上 呢?后来听完《美少女战士》原声带后才发现,“原来我在那么小的时候

87

喜欢

回复

删除

发表回复

评论全部加载完了~

加载更多

订阅

All Rights Reserved

游戏葡萄

版权所有

文章Articles

资讯

深度

海外

专访

专题Topic

人才战

二次元启示录

看懂腾讯

看懂米哈游

联系我们Contact

爆料

hi#youxiputao.com

商务/市场合作

hi#youxiputao.com

简历投递

job#youxiputao.com

Copyright © 2013-2024 | 京ICP备13050684号-1

隐私条款

服务通

关于我们

跨域资源共享 CORS 详解 - 阮一峰的网络日志

跨域资源共享 CORS 详解 - 阮一峰的网络日志

阮一峰的网络日志 » 首页 » 档案

上一篇:浏览器同源政策及其规避

下一篇:理查德·汉明《你和你的

分类:

JavaScript

⇐ 

 ⇒

跨域资源共享 CORS 详解

作者: 阮一峰

日期: 2016年4月12日

CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing)。

它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。

本文详细介绍CORS的内部机制。

(图片说明:摄于阿联酋艾因(Al Ain)的绿洲公园)

一、简介

CORS需要浏览器和服务器同时支持。目前,所有浏览器都支持该功能,IE浏览器不能低于IE10。

整个CORS通信过程,都是浏览器自动完成,不需要用户参与。对于开发者来说,CORS通信与同源的AJAX通信没有差别,代码完全一样。浏览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。

因此,实现CORS通信的关键是服务器。只要服务器实现了CORS接口,就可以跨源通信。

二、两种请求

浏览器将CORS请求分成两类:简单请求(simple request)和非简单请求(not-so-simple request)。

只要同时满足以下两大条件,就属于简单请求。

(1) 请求方法是以下三种方法之一:

HEAD

GET

POST

(2)HTTP的头信息不超出以下几种字段:

Accept

Accept-Language

Content-Language

Last-Event-ID

Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain

这是为了兼容表单(form),因为历史上表单一直可以发出跨域请求。AJAX 的跨域设计就是,只要表单可以发,AJAX 就可以直接发。

凡是不同时满足上面两个条件,就属于非简单请求。

浏览器对这两种请求的处理,是不一样的。

三、简单请求

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。

四、非简单请求

4.1 预检请求

非简单请求是那种对服务器有特殊要求的请求,比如请求方法是PUT或DELETE,或者Content-Type字段的类型是application/json。

非简单请求的CORS请求,会在正式通信之前,增加一次HTTP查询请求,称为"预检"请求(preflight)。

浏览器先询问服务器,当前网页所在的域名是否在服务器的许可名单之中,以及可以使用哪些HTTP动词和头信息字段。只有得到肯定答复,浏览器才会发出正式的XMLHttpRequest请求,否则就报错。

下面是一段浏览器的JavaScript脚本。

var url = 'http://api.alice.com/cors';

var xhr = new XMLHttpRequest();

xhr.open('PUT', url, true);

xhr.setRequestHeader('X-Custom-Header', 'value');

xhr.send();

上面代码中,HTTP请求的方法是PUT,并且发送一个自定义头信息X-Custom-Header。

浏览器发现,这是一个非简单请求,就自动发出一个"预检"请求,要求服务器确认可以这样请求。下面是这个"预检"请求的HTTP头信息。

OPTIONS /cors HTTP/1.1

Origin: http://api.bob.com

Access-Control-Request-Method: PUT

Access-Control-Request-Headers: X-Custom-Header

Host: api.alice.com

Accept-Language: en-US

Connection: keep-alive

User-Agent: Mozilla/5.0...

"预检"请求用的请求方法是OPTIONS,表示这个请求是用来询问的。头信息里面,关键字段是Origin,表示请求来自哪个源。

除了Origin字段,"预检"请求的头信息包括两个特殊字段。

(1)Access-Control-Request-Method

该字段是必须的,用来列出浏览器的CORS请求会用到哪些HTTP方法,上例是PUT。

(2)Access-Control-Request-Headers

该字段是一个逗号分隔的字符串,指定浏览器CORS请求会额外发送的头信息字段,上例是X-Custom-Header。

4.2 预检请求的回应

服务器收到"预检"请求以后,检查了Origin、Access-Control-Request-Method和Access-Control-Request-Headers字段以后,确认允许跨源请求,就可以做出回应。

HTTP/1.1 200 OK

Date: Mon, 01 Dec 2008 01:15:39 GMT

Server: Apache/2.0.61 (Unix)

Access-Control-Allow-Origin: http://api.bob.com

Access-Control-Allow-Methods: GET, POST, PUT

Access-Control-Allow-Headers: X-Custom-Header

Content-Type: text/html; charset=utf-8

Content-Encoding: gzip

Content-Length: 0

Keep-Alive: timeout=2, max=100

Connection: Keep-Alive

Content-Type: text/plain

上面的HTTP回应中,关键的是Access-Control-Allow-Origin字段,表示http://api.bob.com可以请求数据。该字段也可以设为星号,表示同意任意跨源请求。

Access-Control-Allow-Origin: *

如果服务器否定了"预检"请求,会返回一个正常的HTTP回应,但是没有任何CORS相关的头信息字段。这时,浏览器就会认定,服务器不同意预检请求,因此触发一个错误,被XMLHttpRequest对象的onerror回调函数捕获。控制台会打印出如下的报错信息。

XMLHttpRequest cannot load http://api.alice.com.

Origin http://api.bob.com is not allowed by Access-Control-Allow-Origin.

服务器回应的其他CORS相关字段如下。

Access-Control-Allow-Methods: GET, POST, PUT

Access-Control-Allow-Headers: X-Custom-Header

Access-Control-Allow-Credentials: true

Access-Control-Max-Age: 1728000

(1)Access-Control-Allow-Methods

该字段必需,它的值是逗号分隔的一个字符串,表明服务器支持的所有跨域请求的方法。注意,返回的是所有支持的方法,而不单是浏览器请求的那个方法。这是为了避免多次"预检"请求。

(2)Access-Control-Allow-Headers

如果浏览器请求包括Access-Control-Request-Headers字段,则Access-Control-Allow-Headers字段是必需的。它也是一个逗号分隔的字符串,表明服务器支持的所有头信息字段,不限于浏览器在"预检"中请求的字段。

(3)Access-Control-Allow-Credentials

该字段与简单请求时的含义相同。

(4)Access-Control-Max-Age

该字段可选,用来指定本次预检请求的有效期,单位为秒。上面结果中,有效期是20天(1728000秒),即允许缓存该条回应1728000秒(即20天),在此期间,不用发出另一条预检请求。

4.3 浏览器的正常请求和回应

一旦服务器通过了"预检"请求,以后每次浏览器正常的CORS请求,就都跟简单请求一样,会有一个Origin头信息字段。服务器的回应,也都会有一个Access-Control-Allow-Origin头信息字段。

下面是"预检"请求之后,浏览器的正常CORS请求。

PUT /cors HTTP/1.1

Origin: http://api.bob.com

Host: api.alice.com

X-Custom-Header: value

Accept-Language: en-US

Connection: keep-alive

User-Agent: Mozilla/5.0...

上面头信息的Origin字段是浏览器自动添加的。

下面是服务器正常的回应。

Access-Control-Allow-Origin: http://api.bob.com

Content-Type: text/html; charset=utf-8

上面头信息中,Access-Control-Allow-Origin字段是每次回应都必定包含的。

五、与JSONP的比较

CORS与JSONP的使用目的相同,但是比JSONP更强大。

JSONP只支持GET请求,CORS支持所有类型的HTTP请求。JSONP的优势在于支持老式浏览器,以及可以向不支持CORS的网站请求数据。

(完)

文档信息

版权声明:自由转载-非商用-非衍生-保持署名(创意共享3.0许可证)

发表日期: 2016年4月12日

相关文章

2022.10.25: 羊了个羊,如何自己实现(暨"码上掘金"编程挑战赛介绍)

[海报] 稀土掘金正在面向全国举办"首届编程挑战赛",这是展示自己作品的好机会,详情见文后。

2022.05.05: 打包工具 rollup.js 入门教程

rollup.js 是一个 JavaScript 打包工具。本文介绍它的基本用法。

2021.09.29: JavaScript 侦测手机浏览器的五种方法

有时候,前端网页需要知道,用户使用的是手机浏览器还是桌面浏览器。

2021.01.20: 剪贴板操作 Clipboard API 教程

一、简介

浏览器允许 JavaScript 脚本读写剪贴板,自动复制或粘贴内容。

留言(163条)

Se7en

说:

阮老师讲得非常全面透彻,看完这篇文章就会对浏览器的同源策略和跨域请求了解清楚了,堪称经典。

2016年4月12日 07:11

| #

| 引用

杨铮

说:

asp.net web api 中的坑。

web.config 中 remove name="OPTIONSVerbHandler" 需要去掉。

2016年4月12日 08:38

| #

| 引用

光君

说:

可以可以,老师这篇文章很关键。但是想多问一句CORS在哪些场景下应用比较多?

2016年4月12日 09:33

| #

| 引用

Lxxyx

说:

正在最近在纠结跨域请求的相关问题,而已有资料的质量良莠不齐,阮一峰老师的两篇博文真的超级赞。

2016年4月12日 09:55

| #

| 引用

Junyi

说:

Access-Control-Allow-Origin支持多域名:http://junyi.me/blog/s17.html

2016年4月12日 19:44

| #

| 引用

四喜

说:

文中提到“CORS请求默认不发送Cookie”,通过服务端响应 Access-Control-Allow-Credentials: true 来控制。但如果接口依赖Cookie来完成一些处理(比如登录态),那第一次发送CORS请求“默认不发送Cookie”的话,服务端接受不到Cookie,岂不会有问题?

从实验上来看,Access-Control-Allow-Credentials: true 好像并没有控制Cookie是否发送,因为即使之前没有任何CORS请求(自然也没有往客户端发送该Header),第一次CORS请求也会带上所有该域能访问的Cookie。

测试环境:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.110 Safari/537.36

2016年4月13日 10:17

| #

| 引用

阮一峰

说:

@四喜,

我试了一下,如果设为 withCredentials = false ,就不会发送 Cookie 了。如果省略这一行,确实会发送。但 MDN 明确说,默认值是 false。https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/withCredentials

我原来的说法表达得不确切,我改一下。

2016年4月13日 11:19

| #

| 引用

waylau

说:

Access-Control-Allow-Origin 字段,如何表示允许一个以上的网站访问(不是*这种全部),比如 允许 http://api.bob.com、 http://api.alice.com 两个网站。

Access-Control-Allow-Origin 字段能实现吗?我这边试下,好像不行。

2016年4月13日 16:50

| #

| 引用

mrsu

说:

简单请求的 Content-Type 包含 text/plain 而不是 text/html 感觉不科学啊~

2016年4月13日 19:53

| #

| 引用

OMEGA

说:

简单请求包含connection首部,但是文中指出的不符?

(2)HTTP的头信息不超出以下几种字段:

Accept

Accept-Language

Content-Language

Last-Event-ID

Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain

2016年4月15日 11:49

| #

| 引用

张歆琳

说:

4.2节里有笔误Access-Control-Allow-Headers: true 应该是 Access-Control-Allow-Credentials: true

2016年4月16日 00:00

| #

| 引用

阮一峰

说:

@张歆琳:

谢谢指出,已经改正了。

2016年4月16日 11:32

| #

| 引用

skyer

说:

如果浏览器否定了"预检"请求,

----

这个应该是『服务器否定了"预检"请求』吧。

2016年4月18日 18:41

| #

| 引用

迹忆

说:

写的非常好,感谢阮老师的分享

2016年4月19日 13:29

| #

| 引用

文刀

说:

文章写的非常好,又掌握了一个重要的知识点!感谢阮兄分享

2016年4月20日 11:54

| #

| 引用

Sia

说:

有一个问题想请教一下,在淘宝登陆后,打开天猫,会发现也是已登录状态,这是怎么做的呢?

2016年4月24日 10:36

| #

| 引用

GlacJAY

说:

4.2 节里面,「服务器回应的其他CORS相关字段如下」中,有个字段写错了吧?写了两次「Allow-Headers」。

2016年4月26日 10:05

| #

| 引用

大头

说:

看阮老师一篇文章,胜读十本书

2016年4月26日 14:57

| #

| 引用

二点零

说:

学习了,两篇文章讲得非常详细,感谢

2016年5月 5日 15:07

| #

| 引用

小小的大二学生

说:

还有IE的ActiveXObject

2016年5月 8日 21:38

| #

| 引用

纪广财

说:

受教,谢谢阮老师~

2016年5月24日 22:40

| #

| 引用

如理

说:

引用大头的发言:

看阮老师一篇文章,胜读十本书

你看书只看序的吧?

2016年5月26日 17:32

| #

| 引用

echo

说:

引用光君的发言:

可以可以,老师这篇文章很关键。但是想多问一句CORS在哪些场景下应用比较多?

restful api

2016年6月 3日 17:59

| #

| 引用

quay

说:

引用echo的发言:

restful api

有些疑问:

1)为啥看到一些公开的API貌似没有origin

2)restful api 、 web api 、cors 、web service 目前流行哪个做API呢

3) cors IE10才可能,兼容性如何解决呢?

2016年6月11日 22:45

| #

| 引用

cmxz

说:

关于Credentials,重要的不是会不会发送,而是cookie发送到服务端后如果response header中无Access-Control-Allow-Credentials: true,那么浏览器会报异常,js无法拿到跨域请求的response对象

2016年6月19日 00:45

| #

| 引用

甘训奏

说:

我的请求:

```

$.ajax({

type: "POST",

url: "http://192.168.0.103:8081/forum/servlet/HelloServlet",

//contentType:"application/json",

data: {uName:$("#uName").val(), uPwd:$("#uPwd").val()},

dataType: "json",

success: function(data){

$('#resText').empty(); // 清空resText里面的所有内容

var html = '';

$.each(data, function(commentIndex, comment){

html += '

' + comment['username']

+ ':

+ '

';

});

$('#resText').html(html);

}

});

```

服务端接收到后增加CORS处理。

```

response.setContentType("text/html; charset=utf-8");

response.addHeader("Access-Control-Allow-Origin", "*");

response.addHeader("Access-Control-Allow-Methods", "*");

response.addHeader("Access-Control-Max-Age", "100");

response.addHeader("Access-Control-Allow-Headers", "X-Custom-Header,accept, content-type");

response.addHeader("Access-Control-Allow-Credentials", "false");

```

2016年6月22日 13:09

| #

| 引用

甘训奏

说:

===========================================

为什么留言不能超过1200个字,接上一个提问

===========================================

不加 `contentType="application/json"`正常访问后台。增加`contentType="application/json"`后提示:

```

XMLHttpRequest cannot load http://192.168.0.103:8081/forum/servlet/HelloServlet. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8020' is therefore not allowed access.

```

从错误看,应该是preflight (预检)请求涉及到跨域问题了。现在问题是preflight 的请求响应设置在哪边处理呢?

2016年6月22日 13:11

| #

| 引用

潘逸飞

说:

写的超赞!

2016年6月29日 17:03

| #

| 引用

赵帅

说:

阮老师想问你个问题,我目前也是在Cors跨域这块遇到了难题,1.我在复杂请求时,PUT,首先预检通过,可以看到status code:200状态码,2.然后第二次要做真实的修改操作,直接报500状态码,服务器内部错误,响应头里面没有Origin,Headers,Method这三项.请问这是什么情况呢?烦请阮老师帮忙看下。不胜感谢!

2016年6月30日 15:16

| #

| 引用

eviltear

说:

想问阮老师,跨协议请求有类似的解决方案吗?如http请求https,谢谢。

2016年7月25日 10:53

| #

| 引用

Silas

说:

提一点:

做auth时,xhr.setRequestHeader,key 不能是 token 字符串。

2016年8月22日 11:09

| #

| 引用

Slimmer

说:

引用光君的发言:

可以可以,老师这篇文章很关键。但是想多问一句CORS在哪些场景下应用比较多?

我们项目目前使用Restful架构,由于前后不在台服务器,处处需跨源

2016年9月 2日 14:05

| #

| 引用

xylsh

说:

引用Slimmer的发言:

我们项目目前使用Restful架构,由于前后不在台服务器,处处需跨源

我在想,即使不在同一台服务器,如果前台用nginx做请求转发,把不同请求转发到不同服务器,这样,从浏览器的角度来看,域名就没有发生变化,也就不用跨域。我的想法对吗?

2016年9月27日 17:42

| #

| 引用

cmxz

说:

Access-Control-Max-Age字段在webkit的浏览器上默认最大时间为5分钟,若设置超过5分钟则不会生效,代码见https://cs.chromium.org/chromium/src/third_party/WebKit/Source/core/loader/CrossOriginPreflightResultCache.cpp?rcl=1399481969&l=44

另外,chrome实际上有bug,即使Access-Control-Max-Age设置为600,下次请求时依然会发送options请求,此bug在2012年被提出,但至今未修复。具体见 https://bugs.chromium.org/p/chromium/issues/detail?id=131368

2016年10月 8日 11:45

| #

| 引用

cmxz

说:

可以在http://test-cors.org/ 测试

2016年10月 8日 11:46

| #

| 引用

cmxz

说:

我之前的表述可能有问题。

经过测试,chrome现阶段(54.0.2840.50 beta-m (64-bit))是支持对options的请求缓存5分钟的

我之前之所以会觉得没有缓存,是因为我原以为preflight-result-cache是以域名为单位的cache,但看了https://www.w3.org/TR/cors/#preflight-result-cache 后发现cache是以origin+url+credentials+method+header在max-age内cache的,所以不同url(get参数不同也算的)是会发送多次options请求的

2016年10月 9日 15:08

| #

| 引用

第六天魔王

说:

今天正好我女朋友面试,被问到这个问题,我觉得即便是研究生想说透也不是件很容易的事情。

我本人实际项目中倒是遇到过跨域问题,一个业务场景是用户上传图片然后切图后再保存,上传图片到第三方存储后(我用的是aws的s3+cloudfront),前端js类库从cdn获取原图时用的是ajax方法。在s3设置cors策略,在cloudfront设置http预检策略,结合阮老师的文章,基本理解到位了,非常感谢!

2016年10月10日 14:49

| #

| 引用

李超

说:

在3.1节中您讲到:

> 如果Origin指定的源,不在许可范围内,服务器会返回一个正常的HTTP回应。

请问 许可范围 是在什么地方指定的呢?谢谢!

2016年10月16日 10:55

| #

| 引用

billow

说:

目前为止看到的最深入浅出的解释!

2016年10月20日 17:44

| #

| 引用

久保与二弦琴

说:

您好,在测试这个问题的时候,发现即便服务器端不设置Access-Control-Allow-Origin头,服务器依然会返回数据,可以用fiddler抓取到,和设置头信息后的区别只是浏览器页面不显示数据而已。能否表明,CORS设置与否只是影响浏览器是否显示服务器返回的数据,而无法阻止服务器要不要返回数据?

2016年11月 5日 13:24

| #

| 引用

严泽玮

说:

ie8通过XDomainRequest能支持CORS,文中说要不低于ie10,难道我理解错了。

2016年11月17日 17:42

| #

| 引用

赵启发

说:

“上面说到,CORS请求默认不发送Cookie和HTTP认证信息。如果要把Cookie发到服务器,一方面要服务器同意,指定Access-Control-Allow-Credentials字段。”

对于简单请求,其并没有预检请求。也就是说收到服务器响应的时候,简单请求已经发出去了,也就是说简单请求发送的时候不管是带不带cookie,这个决策已经完成了。那么这时候server返回Access-Control-Allow-Credentials字段的意义是什么呢?

1. 告诉浏览器其实服务器并没有处理你发送过来的cookie,假设浏览器发了cookie并期待cookie生效以达成某种目的的话,用来帮助定位问题?

2. 告诉浏览器这个信息,下次再发同样的跨域请求的时候就知道该不该发送cookie了?

2016年11月17日 20:52

| #

| 引用

cxl253386709

说:

最近要把web端已有的应用扩展到移动端h5轻应用上,遇到了跨域访问一个诡异的问题。在服务端设置好Access-Control-Allow-Origin:* ;Access-Control-Allow-Credentials: "true" 后,两个系统做了cas,然后开发环境一切ok。等到项目准备上线时,打包进weblogic,居然发现访问失效。具体表现是当请求的结果超出一定数据量以后(因为可以指定每页条数,所以可以一点点的加返回数据量,当到了一个临界值以后,突然出现问题,比如30条的时候没事,31条突然就没数据了),从浏览器观察返回的response为空。在weblogic开了debug模式,发现后端一切正常没有任何错误,也确实查了数据库也确实返回了。后来为了验证这个问题,把同一个包又放到tomcat上跑,发现能返回数据量的临界值更小了,同一个包放在本地jetty上就没这个问题。所以我怀疑是不是各个应用服务器在处理跨域返回数据量时有一个默认值,可以配置的?我找了文档却没发现有这个设置。百思不得其解,卡了我好几个周了,求大神解惑!!!

今天我又做了几个实验,这个限额大约是20k的样子!!

2016年11月30日 14:36

| #

| 引用

lili

说:

大神,有没有cros跨域请求的具体实例呀?我在使用cros跨域上传文件过程中从后台返回的数据前台接收不到,status是0,急用,麻烦您了

2016年12月13日 17:35

| #

| 引用

DemoorBug

说:

引用Silas的发言:

提一点:

做auth时,xhr.setRequestHeader,key 不能是 token 字符串。

我就遇到了这种问题,angular 拦截器设置了 req.headers['token'] = ‘’; 跨域就无法通过预检测器,请问有什么方法么,我也设置了

res.setHeader('Access-Control-Allow-Headers','token');

但还是无法实现

2016年12月22日 15:43

| #

| 引用

夏笛

说:

cors并不是所有浏览器都支持吧,opera mini就是一个例子,现在做这套策略还应该考虑降级问题

2016年12月30日 14:50

| #

| 引用

arkin

说:

Access-Control-Max-Age 在chrome控制台注意有disabled cache的选项,

不然会被坑,我调了很久也不生效,信好网上看到.提醒一下大家.

2017年1月 4日 17:54

| #

| 引用

和珅

说:

Access-Control-Request-Method 这个方法是告诉服务端我将要用什么方法请求数据,而不是方法的罗列。

补充withCredentials = true; 设置Access-Control-Allow-Credentials = true的同时Access-Control-Allow-Origin的值不能为“*”,必须设置一个完整的域,只允许一条。

2017年1月 9日 10:02

| #

| 引用

bsc2xp

说:

引用cmxz的发言:

关于Credentials,重要的不是会不会发送,而是cookie发送到服务端后如果response header中无Access-Control-Allow-Credentials: true,那么浏览器会报异常,js无法拿到跨域请求的response对象

这么解释看得才明白,文章里说的没理解

2017年2月 9日 09:21

| #

| 引用

leaf

说:

引用quay的发言:

有些疑问:

1)为啥看到一些公开的API貌似没有origin

2)restful api、 web api 、cors 、web service 目前流行哪个做API呢

3) cors IE10才可能,兼容性如何解决呢?

1)应该是那些应用有一个后台服务器,后台服务器调用的API

2)restful api 是 web api 中的一种吧

cors 只要浏览器 xhr 跨域请求都要面对的问题,和什么形式 api 无关

web service 是很早之前的技术,现在应该是不流行了

3)JSONP

2017年2月21日 16:31

| #

| 引用

茉莉

说:

引用Sia的发言:

有一个问题想请教一下,在淘宝登陆后,打开天猫,会发现也是已登录状态,这是怎么做的呢?

自己感觉是用同一个数据库吧 起码是用户表 订单表 之类的 通用的会有关联

2017年2月23日 18:19

| #

| 引用

刘欣(Lx15)

说:

阮老师您好,我测试了一下。。。。在前后端分离的情况下,前端发put的非简单请求,并不能够跨源,这是为什么呢? 后端采用node 接收请求。

在前后端不分离的情况下,前端发put的非简单请求,是可以跨源的。

2017年2月24日 11:43

| #

| 引用

吴宏伟

说:

引用杨铮的发言:

asp.net web api 中的坑。

web.config 中 remove name="OPTIONSVerbHandler" 需要去掉。

还真碰到这个坑了。

2017年2月24日 19:58

| #

| 引用

Leesson

说:

感谢,介绍的很详细。

另外请问,如果返回头里包含两个Access-Control-Allow-Origin符合规范吗?比如返回头同时包含如下两个:

Access-Control-Allow-Origin:www.origin.com //(请求发出域名)

Access-Control-Allow-Origin:*

在实际中遇上过上述问题,后台代码和IIS分别为返回头添加了Access-Control-Allow-Origin。当请求发出域名和接收域名(后台)是同一域名时可正常得到结果,但不是统一域名时就会报跨域错误。

阮老师能帮忙解释一下吗?谢谢

2017年2月27日 00:23

| #

| 引用

Ryan

说:

看文章的说法,浏览器决定是否跨域,那么服务端呢?简单的跨域,浏览器带着cookie请求服务器,服务器设置false,则不接收cookie?事实上cookie已经加载到request里了。

第二个问题,简单的跨域中,如果服务端部允许跨域,那么服务端是直接返回空还是按照正常的逻辑返回了数据,只是到浏览器的时候被浏览器给拦截了?

2017年3月30日 23:31

| #

| 引用

vic

说:

@Ryan:

肯定啊 都是浏览器,如果不是浏览器 就不存在这个问题 比如服务器端程序 想请求谁就请求谁 ,

2017年3月31日 11:16

| #

| 引用

ouyang

说:

预检结果

Response Headers

Allow:GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS, PATCH

Content-Length:0

Date:Fri, 31 Mar 2017 06:12:56 GMT

Request Headers

Accept:*/*

Accept-Encoding:gzip, deflate, sdch

Accept-Language:zh-CN,zh;q=0.8

Access-Control-Request-Headers:authorization

Access-Control-Request-Method:POST

Connection:keep-alive

Host:10.220.17.121:8080

Origin:http://10.220.18.113:8020

Referer:http://10.220.18.113:8020/xb/wx/201703013/login.html

User-Agent:Mozilla/5.0 (Linux; Android 5.0; SM-G900P Build/LRX21T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36

如何让浏览器通过Origin呢 怎么设置?

2017年3月31日 14:20

| #

| 引用

龙顺

说:

我只能说,相见恨晚呐!看了几篇阮老师的博客下来,发现内容讲解都非常细致,很难找到比阮老师的更适合初学者的教程了。

关于JSONP,“JSONP的优势在于支持老式浏览器,以及可以向不支持CORS的网站请求数据”。支持老式浏览器是确实是其优势,但像不支持CORS的网站请求数据,我觉得就不是它的优势了,因为后端代码还是得针对JSONP做出相应的调整(返回json字符串的部分需要用传过去的回调函数名包起来),也很麻烦。反而CORS的方式,只需要在后端代码的过滤器上加上相应的响应头就行了,来得更方便。

2017年4月 7日 00:19

| #

| 引用

gorden

说:

阮老师,感谢您的文章。现在有一些不明白的地方希望跟你请教一下:

服务器对于预检请求和实际请求是需要用不同的方法去拦截吗?还是这两个请求都是由同一个方法去处理的

2017年4月12日 23:34

| #

| 引用

赵启发

说:

https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Access_control_CORS

这里找到答案了:

“因为这是一个简单 GET 请求,所以浏览器不会对其发起“预检请求”。但是,如果服务器端的响应中未携带 Access-Control-Allow-Credentials: true ,浏览器将不会把响应内容返回给请求的发送者。”

2017年5月 3日 16:16

| #

| 引用

j.zong

说:

阮老师,3.1节中,【如果Origin指定的源,不在许可范围内,服务器会返回一个正常的HTTP回应。浏览器发现,这个回应的头信息没有包含Access-Control-Allow-Origin字段】,这句话有误吧?如果Origin源不在指定的许可范围内,回应的头信息也会包含Access-Control-Allow-Origin字段吧,只是它的值与Origin源不匹配,就会执行onerror错误事件驱动程序

2017年5月 3日 21:18

| #

| 引用

龙海洋

说:

一个post跨域请求在“预检”请求OPTIONS中Origin为什么会为null,并且会报错:

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 401.

OPTIONS请求http头部信息如下:

Accept:*/*

Accept-Encoding:gzip, deflate, sdch, br

Accept-Language:zh-CN,zh;q=0.8

Access-Control-Request-Headers:authorization

Access-Control-Request-Method:POST

Connection:keep-alive

Host:chinapopin.com

Origin:null

User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.96 Safari/537.36

2017年5月10日 10:08

| #

| 引用

syd_2011

说:

引用严泽玮的发言:

ie8通过XDomainRequest能支持CORS,文中说要不低于ie10,难道我理解错了。

xDomainRequest 只支持post,get 不给带cookie等等 大多数情况下等于没什么用

2017年5月16日 19:11

| #

| 引用

阿豪

说:

厉害了 阮老师,收获很多

2017年6月 1日 09:48

| #

| 引用

阿辉

说:

阮老师,这样看来,跨域始终都需要服务端支持才能实现对吗? 并不只是纯粹前端设置就能成功的吗?

2017年6月 3日 17:54

| #

| 引用

夜的眼睛

说:

真心厉害,还是老师讲的简单易懂,一点就通!

2017年6月 7日 23:34

| #

| 引用

贾越

说:

没看懂 谁来教下我 前端和node 怎么设置?

2017年6月13日 13:35

| #

| 引用

谷雨

说:

引用茉莉的发言:

自己感觉是用同一个数据库吧 起码是用户表 订单表 之类的 通用的会有关联

应该是通过CAS做的单点登录认证(SSO)

2017年6月23日 11:34

| #

| 引用

daoSs

说:

怎么有这么好的文章,结合工作中的实践,让我对CORS有了非常清楚的认识。

2017年6月28日 12:06

| #

| 引用

ifu25

说:

引用杨铮的发言:

asp.net web api 中的坑。

web.config 中 remove name="OPTIONSVerbHandler" 需要去掉。

这真是绝世大坑!我搞了两天,查了无数资料,竟然有那么多网站说要把OPTIONSVerbHandler和WebDAV删除,事实上把OPTIONSVerbHandler删除了才会造成OPTIONS失败!

难道是部分环境下会这样?

总结一下我的解决方案(IIS10 + asp.net web api):

1、IIS中增加响应头

Access-Control-Allow-Origin:*

Access-Control-Allow-Headers:Content-Type

2、web.config中把“”删掉

仅此而已~

2017年7月 5日 10:50

| #

| 引用

~~~~

说:

post请求变成了options,请问该怎么设置呢?

2017年7月17日 11:47

| #

| 引用

刘建

说:

我按照上面配置的,怎么还报这个错误,求指教

Refused to set unsafe header "Access-Control-Request-Method"

2017年7月21日 18:03

| #

| 引用

前端菜鸟

说:

复杂请求Content-Type必须为application/json吗还是可以为其他的

2017年7月21日 18:06

| #

| 引用

weiwei

说:

IE10以下怎么办

2017年8月 3日 11:45

| #

| 引用

xiongzhe

说:

恍然大悟,学习了!

2017年8月 4日 09:40

| #

| 引用

王叶深

说:

如果浏览器否定了"预检"请求,会返回一个正常的HTTP回应,但是没有任何CORS相关的头信息字段

这里应该是 服务器否定了预检请求吧。

请教下,如果服务器否定了预检请求,那应该返回什么呢? 状态码应该是403还是200?是否继续往下执行程序?谢谢

2017年8月 4日 15:29

| #

| 引用

xhuanhuan

说:

想请教阮大大关于cors跨域的安全问题,Access-Control-Allow-Origin限定了域名的情况下,还会有什么安全问题呢?

2017年8月 5日 21:02

| #

| 引用

nihao

说:

ajax不就是用xmlhttprequest实现的吗 为何单拿出来ajax

2017年8月20日 11:19

| #

| 引用

伯格

说:

不对啊!前一个文章里您是这么说的。

“同源政策规定,AJAX请求只能发给同源的网址,否则就报错。”

按您的说法,跨域了就直接报错了,怎么会发出去呢?

而且我自己实验了一下,我们公司的接口都是可以跨域的,访问方法和平时发送ajax请求没区别。

所以是不是所谓跨域不能请求ajax指的是,后端通过Access-Control-Allow-Origin来限制跨域请求,而不是浏览器限制你发送ajax跨域请求?

2017年9月22日 17:37

| #

| 引用

lant

说:

cors简单请求不是说不能超过下面的字段么:

Accept

Accept-Language

Content-Language

Last-Event-ID

Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain

第一个简单请求的例子中就有

Host

Connection

User-Agent

这些都不再上面的字段中啊, 怎么理解阮大神说的 不能超过如下字段

2017年9月26日 15:08

| #

| 引用

lz

说:

老师啊, 我前端端口是8699,后台端口是8088,后台登录请求里面设置cookie是不是设置不了啊?为什么下次后台读取cookie的时候,读取不到cookie

2017年11月 2日 15:57

| #

| 引用

Ryze

说:

干货充足,没有太多的废话,赞^32!

2017年11月23日 14:59

| #

| 引用

残心

说:

阮老师您好:

我想咨询您个问题,当我进行跨域的post请求,这个请求为非简单请求的时候,我想要携带cookie,浏览器会做出一次预检请求,但是这次预检请求是并不携带cookie的,这就导致了服务端又新生成了一个cookie(然而这个cookie并用不上),请问一下是不是我哪里操作错误了还是其他什么情况~

fetch("http://localhost:3000/login", {

method: "post",

mode: "cors",

credentials: "include",

headers: {'Content-Type': "application/json"}

});

同理使用jq的ajax也一样

$.ajax({

url: 'http://localhost:3000/login',

type: 'post',

xhrFields: {

withCredentials: true

},

headers:{'Content-Type': "application/json"}

});

并且jq请求回来的cookies在控制台里面看不到,当再次请求的时候却不知道缘何携带上了上次返回设置的cookie。。。但是fetch的请求可以在控制台看到返回的设置的cookie。。。

不知道问题出在哪里,烦请老师解答,不胜感激~

2017年12月14日 14:46

| #

| 引用

df

说:

dfsd

2017年12月21日 14:35

| #

| 引用

hzj629206

说:

@伯格:

你用的浏览器已经支持CORS了吧。不支持CORS的浏览器应该是发不出去。

2018年1月 5日 11:27

| #

| 引用

Lx13

说:

帮助挺大的,谢谢阮老师

2018年1月19日 13:30

| #

| 引用

许杰

说:

@阮一峰,如果浏览器否定了"预检"请求,会返回一个正常的HTTP回应,但是没有任何CORS相关的头信息字段。这时,浏览器就会认定,服务器不同意预检请求,因此触发一个错误,被XMLHttpRequest对象的onerror回调函数捕获。控制台会打印出如下的报错信息。

这里面有个错误吧,应该说服务器否定了“预检”请求,怎么变成浏览器了。

2018年2月 6日 11:08

| #

| 引用

HGW-XX

说:

服务器是不会对什么预检查请求做否定的,仍然会正常200返回,只是一旦浏览器发现返回中无跨域许可的相关设置,就可在浏览器的console中报异常了,也就不会再发正式的请求了,所以是浏览器自己把自己给否定了

2018年2月26日 20:33

| #

| 引用

HGW-XX

说:

引用久保与二弦琴的发言:

您好,在测试这个问题的时候,发现即便服务器端不设置Access-Control-Allow-Origin头,服务器依然会返回数据,可以用fiddler抓取到,和设置头信息后的区别只是浏览器页面不显示数据而已。能否表明,CORS设置与否只是影响浏览器是否显示服务器返回的数据,而无法阻止服务器要不要返回数据?

我觉得您说的很对,好像就是这么一回事,我之前自己简单测试时也发现这个情况,所以我认为,跨域请求只不过是浏览器自己给自己划得底线和操守…,要真是它觉得有没有access-control-allow-origin也无所谓的话,所不定照样请求过去,也没有什么问题

2018年2月26日 20:37

| #

| 引用

HGW-XX

说:

阮老师,您好,看了您的这篇文章,感觉跨域请求的整个来龙去脉,算是基本明白了,

但是还有一个问题,是不是 简单请求的情况下,就算服务器返回的响应头中,没有access-control-allow-origin的设置,但后端的服务并不会受影响,后端仍然会针对“简单请求”提供服务,只不过是浏览器自己比较高分亮节,不去处理返回的数据,

是这样的吗,那跨域请求岂不是对于后端来说,仍然不是很安全, 除非在 比如Spring的filter中将跨域的请求进行过滤才行?

2018年2月26日 20:42

| #

| 引用

刘曦光

说:

在介绍简单请求和复杂请求的地方:

Content-Language 是不是打错了?应该是 Content-Length

2018年3月22日 10:05

| #

| 引用

lindahuo

说:

阮老师,关于您文章里面说的:“Access-Control-Allow-Credentials 的值表示是否允许发送 Cookie”,我在 MDN 中文版本里面没看到有这个意思啊,MDN 只是说:“它指定了当浏览器的 credentials 设置为 true 时是否允许浏览器读取 response 的内容,同时简单 GET 请求如果响应中不包含该字段,这个响应将被忽略掉”。

2018年4月 3日 17:10

| #

| 引用

Ak_allen

说:

Access-Control-Expose-Headers 里面加了 Set-cookie 的白名单,不过客户端 ajax xhr.getResponseHeader*("") 获取到还是 null 怎么回事

2018年4月 4日 07:57

| #

| 引用

chj

说:

阮老师你好,关于这个跨域我最近有个问题

我电脑本机上用vue-cli的开发环境,去请求域名服务器的接口,我设置了

Axios.defaults.withCredentials = true;

后端是php代码

if(isset($_SERVER["HTTP_ORIGIN"])) {

header('Access-Control-Allow-Origin:'.$_SERVER["HTTP_ORIGIN"]);

}

header('Access-Control-Allow-Methods:OPTIONS, GET, POST');

header('Access-Control-Allow-Headers:x-requested-with');

header('Access-Control-Max-Age:86400');

header('Access-Control-Allow-Credentials:true');

但是我在chrome network 中查看request header 还是没有发现携带cookie

关于这方面,我看了其他的文章有说设置domain 但是document.domain 又被禁止,document.cookie = "domain=xxx.com"(xxx.com 是我请求的接口的网站域名)依旧不行

我在这些设置中有些混乱,我始终没有把我本地的cookie 携带过去,后端要接受cookie 在登录状态判断。

请教阮老师。我是否哪里遗漏了,还是做错了?还需要什么配置吗?谢谢阮老师

2018年4月14日 16:27

| #

| 引用

周周

说:

@甘训奏:

这可能是在服务器没有提供对Options请求的处理,参考:Spring mvc解决跨域请求:Response to preflight request doesn't pass access control check

2018年4月16日 09:52

| #

| 引用

潘明杰

说:

老师

我发送的请求时origin是null怎么解

2018年4月17日 14:42

| #

| 引用

柴全起

说:

阮老师你好,我想问下,后端设置CORS了,但是还是报错,好像是浏览器拦截了,前端需要设置xhr.withCredentials = true就行了吗?

2018年4月23日 12:02

| #

| 引用

迪壳

说:

阮老师,您好

关于 Access-Control-Allow-Credentials 的有一部分不太理解

有提到说 Access-Control-Allow-Credentials为true的时候才发送cookie

但是这个时候不是已经接收到服务器的回应了吗? 这样的话第一次请求不是无法携带cookie吗?

2018年7月11日 22:59

| #

| 引用

ericxu1983

说:

这篇文章写的不太好,找了一篇英文的tutorial,写的更好一些:https://www.html5rocks.com/en/tutorials/cors/

2018年7月17日 10:33

| #

| 引用

besthyhy

说:

Spring Boot 一个 @CrossOrigin 就可以跨域访问了。 但是本地调试的时候,https://localhost:63343 的页面访问不通 https://localhost:8488的接口。

有办法吗?感激不尽!

2018年7月19日 00:37

| #

| 引用

JavanLu

说:

"If request method is not a case-sensitive match for any method in methods and is not a simple method, apply the cache and network error steps."

----参见 https://www.w3.org/TR/cors/#preflight-request

由于 GET | POST | HEAD 是简单方法,在通过预检请求后,即使 Access-Control-Allow-Methods 中没有返回 GET | POST | HEAD , 这三种类型的非简单请求仍然会成功。

2018年7月26日 16:32

| #

| 引用

小心鲨鱼

说:

阮老师,我们公司后端验证登录系统,验证所有的请求的cookie,但是options请求没有携带cookie所以直接被重定向到了登录界面,所以option请求是否可以携带cookie吗?

2018年8月 1日 10:15

| #

| 引用

Michael

说:

写的结构明确易读,思路很清晰,感觉以后搜索的时候要先看阮老师有没有相关的文章了。

建议把下方 的评论折叠一下,看到进度条好长,差点被吓跑了。哈哈...

2018年8月27日 10:09

| #

| 引用

刘曦光

说:

跨越方面也可以看看这文章:https://segmentfault.com/a/1190000011145364

2018年9月18日 14:26

| #

| 引用

陈宏伟

说:

写的漂亮,迷糊了这么长时间,终于知道了原理

2018年10月11日 16:05

| #

| 引用

周振宇

说:

cookie 可以跨域不可以跨域名,子域名也是可以共享顶级域名下的cookie的,response可以写入任意的domain,但是request无法将其他的域名下的cookie写入,document.cookie也是同样

2018年10月15日 17:19

| #

| 引用

baibai

说:

@甘训奏:

我遇到了和你同样的问题,我是在火狐浏览器上解决了这个问题。chrome上有bug。

2018年10月18日 14:21

| #

| 引用

aaaa

说:

options 请求返回302. 浏览器没跳转location。 可能是哪的原因。

2018年10月25日 15:23

| #

| 引用

茹俊巧

说:

老师,您好

关于预检那块,我有点迷惑。您文章中写道,“预检”用的方法是OPTIONS,一会又说道“PUT”,到底是哪种呢?

2018年11月 2日 16:36

| #

| 引用

TnTomato

说:

更详细的介绍 https://www.html5rocks.com/en/tutorials/cors/

2018年11月19日 11:06

| #

| 引用

易水寒

说:

关注你好久了,受益匪浅

2018年11月21日 19:57

| #

| 引用

彬彬

说:

您好,看了您写的文章,有个小疑问,想问一下,就是按照您写的标准,发现有的请求不属于简单请求也不属于非简单请求。

2018年11月29日 11:06

| #

| 引用

tyx1703

说:

阮老师,简单请求的条件不只是您列的两大条件,根据mdn的文档,还有两个条件也需要同时满足:

1. 请求中的任意XMLHttpRequestUpload 对象均没有注册任何事件监听器;XMLHttpRequestUpload 对象可以使用 XMLHttpRequest.upload 属性访问。

2. 请求中没有使用 ReadableStream 对象。

https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Access_control_CORS

2018年11月29日 17:53

| #

| 引用

刘旭伟

说:

阮大神,我设置了全局跨域,但还是跨域不成功。可以确定代码没问题,就是不能跨域。您能解释一下这个问题吗?

2018年11月30日 17:44

| #

| 引用

蓦然木然

说:

写得很详细,在网上百度了半天,零零碎碎的

2018年11月30日 18:13

| #

| 引用

说:

请问下能不能给options请求加上一个token之类得?

2018年12月11日 18:21

| #

| 引用

路过

说:

'如果浏览器否定了"预检"请求,会返回一个正常的HTTP回应,但是没有任何CORS相关的头信息字段。'这句中的浏览器是不是应该是服务器否定了预检请求?

2018年12月20日 22:48

| #

| 引用

键盘猫

说:

引用严泽玮的发言:

ie8通过XDomainRequest能支持CORS,文中说要不低于ie10,难道我理解错了。

确实是支持的,红宝书上有写。推测是阮老师为了简明地表述,没有特意写出XDR。

2018年12月31日 16:15

| #

| 引用

patrick

说:

读老师一篇文章真的胜读一本书

2019年2月 9日 03:03

| #

| 引用

zzqsmile

说:

给个赞,讲的非常好

2019年3月 1日 16:53

| #

| 引用

我服慕容格

说:

写的很好

2019年3月 9日 19:35

| #

| 引用

我服慕容格

说:

引用cmxz的发言:

关于Credentials,重要的不是会不会发送,而是cookie发送到服务端后如果response header中无Access-Control-Allow-Credentials: true,那么浏览器会报异常,js无法拿到跨域请求的response对象

正解,其实这两个开关一个管服务器,一个管客户端,客户端fetch设了credentials设了include,就一定会发送目标网站的cookie,服务器如果credentials即使不设为ture,照样会返回正确内容(取决于服务器开发工程师),但有一点,如果你服务器不设为true,浏览器就认为你违反了规则,把服务器返回的内容屏蔽掉(虽然屏蔽掉了),这就会出现,返回码是200,但无正确内容收到的情况。

2019年3月10日 17:55

| #

| 引用

我服慕容格

说:

引用Sia的发言:

有一个问题想请教一下,在淘宝登陆后,打开天猫,会发现也是已登录状态,这是怎么做的呢?

因为登录的是淘宝,所以初次打开天猫时,是没有天猫的cookie的,但按照CORS的规则,浏览器不可能将淘宝的cookie发给天猫。

也有可能用的是无状态的jwt,猜的,没细

2019年3月10日 20:02

| #

| 引用

我服慕容格

说:

@cxl253386709:

依小仙来看,

一个是至少貌似当Access-Control-Allow-Credentials:指定为 "true"时,Access-Control-Allow-Origin:不能指定为*,必须指定为具体的域名。

二个是你后续出现的若干问题,是否与第一条有关?

三个是服务器确实有返回,日志也看到了,哪就是客户端实际上也收到了,甚至返回200,但就是不给你,浏览器在cors时,只要发现服务器返回的headers有一点不匹配cors规则,就干这事,而且还不给你原因(还给你返回个200)

这回复过去好久了,如果层主还在,不防说说原因

2019年3月11日 11:22

| #

| 引用

潘晓瑜

说:

不能接收到返回值是因为什么

2019年3月29日 10:33

| #

| 引用

Damon

说:

总算找到解决这个问题的方法了

2019年5月 6日 14:25

| #

| 引用

二狗子

说:

1.我的情况是跨域问题时报、时不报。有时可以正常访问,有时又会报:has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource。

2.nginx有代理,java代码也有写过滤器。网上查的试了不少,情况依旧。

3.最早是有跨域问题,访问不到后端工程接口,加了过滤器(加 response.setHeader)后便可正常访问。

4.最近又报此错,却也间或可正常访问。间或访问中突然又报错:502(Bad Gateway) ...

个人甚为迷惑,求指点方向 ...

2019年5月14日 10:40

| #

| 引用

阿凡提

说:

引用Sia的发言:

有一个问题想请教一下,在淘宝登陆后,打开天猫,会发现也是已登录状态,这是怎么做的呢?

这个应该是 Session的登录态共享

2019年7月 4日 23:24

| #

| 引用

阿凡提

说:

引用aaaa的发言:

options 请求返回302. 浏览器没跳转location。 可能是哪的原因。

cookie没带到服务端把

2019年7月 4日 23:29

| #

| 引用

李某某

说:

如果是application/json的get请求呢?算是非简单请求吗?会发送options预检请求吗?

2019年8月 1日 16:39

| #

| 引用

yin

说:

引用李某某的发言:

如果是application/json的get请求呢?算是非简单请求吗?会发送options预检请求吗?

get 请求的content type 在服务端都只会读取 像是 application/x-www-form-urlencoded 的格式,你

也无法在get request 的 data body 加入json数据

2019年8月10日 13:46

| #

| 引用

小小幸

说:

nginx解决复杂请求跨域的时候需加上 aweys 参数 ,

eg:add_header 'Access-Control-Allow-Origin' "$http_origin" always;

原因:As of Nginx 1.7.5, add_header supports an "always" parameter which

allows CORS to work if the backend returns 4xx or 5xx status code.

参考资料:https://gist.github.com/Stanback/7145487

2019年8月23日 11:14

| #

| 引用

deping

说:

这是我看到的最清晰的跨域请求说明,比MDN的还清晰。

2019年9月16日 19:17

| #

| 引用

赵铁柱

说:

阮一峰老师您好,看了您的跨域文章以后我有一事不明,您说

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...

这是一个简单请求,可是,Host头和Connection头并没有符合您说的第二条规则啊,为啥他还是一个简单请求呢???

2019年9月25日 11:52

| #

| 引用

NorunN

说:

Access-Control-Allow-Origin

它的值要么是请求时Origin字段的值,要么是一个*,表示接受任意域名的请求

如果不设置为*,想支持多个域名改怎么办呢?

2019年9月29日 15:39

| #

| 引用

Tim

说:

引用NorunN的发言:

Access-Control-Allow-Origin

它的值要么是请求时Origin字段的值,要么是一个*,表示接受任意域名的请求

如果不设置为*,想支持多个域名改怎么办呢?

maybe 支持正则吧?

2019年11月 4日 14:41

| #

| 引用

Andel

说:

找了好多有关跨域的资料,还是阮一峰老师说得最明白最有条理,感谢!

2019年11月23日 18:11

| #

| 引用

张三

说:

亲测在chrome浏览器中 Content-Type: application/json;的GET/POST请求不会发出预检请求,是不是application/json的请求也在简单请求之列呢?

2019年12月16日 16:53

| #

| 引用

温某某

说:

受教了,感谢阮老师

2019年12月23日 21:11

| #

| 引用

Jon

说:

引用赵铁柱的发言:

阮一峰老师您好,看了您的跨域文章以后我有一事不明,您说

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...

这是一个简单请求,可是,Host头和Connection头并没有符合您说的第二条规则啊,为啥他还是一个简单请求呢???

这里得补充一下, 是你手!动!添加的header 要在安全headers 列表中.

浏览器会自动添加一些header, 这些不会触发预检

详情请看:

https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#Simple_requests

2019年12月28日 04:03

| #

| 引用

阿白

说:

老师,我所有都配置好了,但是谷歌会返回302是什么情况

2019年12月29日 18:48

| #

| 引用

阿飞

说:

服务器端如果不支持跨域,收到请求,比如写入表一条数据,是不是也会正常处理?只是返回数据没有allow信息,浏览器认为异常/失败了。

2020年3月 4日 18:13

| #

| 引用

Sage

说:

重温经典,谢谢阮老师。

2020年4月14日 15:12

| #

| 引用

Always_July

说:

引用NorunN的发言:

Access-Control-Allow-Origin

它的值要么是请求时Origin字段的值,要么是一个*,表示接受任意域名的请求

如果不设置为*,想支持多个域名改怎么办呢?

能不能后端判断根据Origin改变Access-Control-Allow-Origin

2020年4月21日 18:13

| #

| 引用

光影

说:

阮一峰老师,CORS能针对 除了Http协议之间的通信 的其他协议进行跨域吗?跨域既然包括了协议的不同,那么CORS是否有针对这一块儿做处理呢?还是说只能针对http,而协议之间的跨域是通过其他方式实现的?

2020年5月20日 20:17

| #

| 引用

YX

说:

补充一下,给xhr文件上传加了进度监听就会变成非简单请求https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#Simple_requests

2020年6月30日 17:47

| #

| 引用

野原新之助

说:

引用赵帅的发言:

阮老师想问你个问题,我目前也是在Cors跨域这块遇到了难题,1.我在复杂请求时,PUT,首先预检通过,可以看到status code:200状态码,2.然后第二次要做真实的修改操作,直接报500状态码,服务器内部错误,响应头里面没有Origin,Headers,Method这三项.请问这是什么情况呢?烦请阮老师帮忙看下。不胜感谢!

预检通过不能只看状态码,要看是否有Access-Control-……字段,有无可能是这里的问题。

2020年7月15日 10:49

| #

| 引用

katherine

说:

如果ResponseHeader中设置: X-Content-Type-Options: nosniff,那么即便是Access-Control-Allow-Origin:* 貌似也不能使用jsonp实现跨域请求,麻烦大神指教

2020年8月 6日 10:19

| #

| 引用

liufei

说:

引用张三的发言:

亲测在chrome浏览器中 Content-Type: application/json;的GET/POST请求不会发出预检请求,是不是application/json的请求也在简单请求之列呢?

不是不会发 是network面板里面只能看到一个 如果看all里面能看到的 还有 这个跟chrome版本也有差异

2020年9月 4日 17:23

| #

| 引用

RickXu

说:

讲的真是太棒了,简单明了,无废话,每个字都有意义。很少看到这么优秀的文章!

2020年12月29日 17:37

| #

| 引用

99

说:

大牛,这里好像有个不严谨的地方:

Access-Control-Max-Age

OPTIONS请求返回结果未通过校验,这个缓存时间不会生效

2020年12月30日 11:37

| #

| 引用

yuki070

说:

我遇到一个问题,一个post的跨域请求,在不设置header的时候,后端能收到,加上header后,后端就收不到了,貌似在浏览器就被拦截了。

const ajax = new XMLHttpRequest();

ajax.open('post', 'http://localhost:8083/bigscreen/module/add', true);

// ajax.setRequestHeader('X-Custom-Header', 'value');

ajax.send();

ajax.onreadystatechange = function() {

if (ajax.readyState === 4 && ajax.status === 200) {

console.log(ajax.responseText);

}

};

浏览器network里看到“Provisional headers are shown”这样一个提示

2021年1月 5日 09:58

| #

| 引用

说:

非常感谢阮一峰老师

2021年3月23日 15:52

| #

| 引用

状态的状

说:

我也不太理解这个同源策略,似乎只是浏览器的限制,服务器该做的都做了,只是浏览器阻止你拿到response。如果进行删更的请求,那该做的都做了,只是拿不到返回值而已。

我是不是应该在服务端过滤一下origin,感觉似乎只是平添了麻烦。如果我已经做了token验证了,那还有对origin做验证的必要嘛。

2021年6月16日 15:52

| #

| 引用

wangwei

说:

老师,请教一个关于跨域的问题:使用application/json之后,用Chrome可以请求服务器资源,但是在mac下面用Safair就始终报错。

XMLHttpRequest cannot load http://yunprint.gmgrasp.com.cn/PrintApi/GetStyleInfo. Request header field Content-Type is not allowed by Access-Control-Allow-Headers.

2021年8月26日 11:33

| #

| 引用

lmlife2021

说:

@OMEGA:

阮兄说漏了,请求头应该还会包含浏览器自动添加的那些。比如你说的connection, 还有referer,User-Agent等等

2021年9月 4日 16:13

| #

| 引用

明志

说:

百思不得其解的时候,就想到阮老师了。谢谢分享

如果能把留言区折叠一下就更好了,一开始看到进度条好长,心理上有点被吓到。哈哈

2021年12月 5日 01:19

| #

| 引用

Joe

说:

阮老师的文章,结构清晰,语言精炼,逻辑感强,非常精彩啊,跟着老师学到了很多东西

2022年2月18日 12:15

| #

| 引用

tnndworlds

说:

Access-Control-Allow-Origin 0 表示什么呢。小红书的接口,有些云服务是可以访问,有些访问不了,猜测是因为域名引起的,*和具体的域名都知道什么意思,这个0就不理解了

2022年2月22日 21:38

| #

| 引用

fallorest

说:

老师,请问移动端的webview有没有这个CORS的限制?

2022年4月12日 15:21

| #

| 引用

飞黄腾达

说:

小阮有进步!

2022年6月14日 15:38

| #

| 引用

谷达

说:

请问阮老师,

现在有了比如axios的反向代理不是更好吗, 这两个用来干嘛 ? ?

2022年7月22日 16:24

| #

| 引用

萌新

说:

感谢阮老师,因为要带Cookie单点登录重定向接口挤掉前面的用户,网络查了半天都是错的,来老师这里一看就成功了

2023年7月26日 14:56

| #

| 引用

我要发表看法

您的留言

(HTML标签部分可用)

您的大名:

«-必填

电子邮件:

«-必填,不公开

个人网址:

«-我信任你,不会填写广告链接

记住个人信息?

正在发表您的评论,请稍候

«- 点击按钮

Weibo |

Twitter |

GitHub

Email: [email protected]

什么是CROS? - 知乎

什么是CROS? - 知乎切换模式写文章登录/注册什么是CROS?CROS扣子让个体一键进入区块链世界,自创建区块链账本和自设计TokenC Capital资本, R resources 资源, O operation 运营, S synchronization 协同,顾名思义,CROS是生产要素协作的工具。CROS是一个基于区块链基础架构的开放式商业平台,适用于所有希望利用区块链技术来改善和自动处理商业流程的个体和公司,它提供了一套行业标准工具来创建和管理区块链应用,一个开放的协议使参与者可以通过自动化执行的工作流来进行商业协作。CROS的核心战略模式为1+1+N,即是1个平台+1个价值中介+N个生态。一个CROS生态平台(底层)CROS是一个适用于所有希望利用区块链技术来改善和自动处理商业流程的实体。它提供了一套行业标准工具来创建和管理企业的私有链,以及一个使得参与者可以通过工作流自动处理来进行协作的开放协议。CROS的最终目的是通过桥接分散的商业系统,低成本的帮助所有实体参与进全球交易网络中去,促进资金、货品和服务的流通。让商家能一键进入区块链世界,类似于淘宝对商家的支持作用。按照CROS白皮书实施进行中,目前,CROS技术团队已经完成第一阶段目标了,一键生成生态链、自定义Token、模块化智能合约。功能演示系统可以了解:http://www.dome.cros.work (PC端)。一个锚定法定价值WBC(微贝,价值中介Token)WBC(微贝),一个落地在当前的经济与金融环境中,并能稳定价值(相对于法币)实现去中心的中介。WBC也相当于数字版的支付宝,既能价值互换,也能锚定法币的数字储存货币。具有价值稳定,全网流通、双向兑换的特征。CROS已完成微贝包包Dapp(钱包)开发,主要承载所有CROS生态Token资产管理及交易。该应用已经进入内侧阶段,预计今年八月份就可以上线使用。多个生态应用场景例如:CROS 的艺术ATC、法律LYC、产品信用CTC、扶贫GYC、CROS BANK 等等,这些都为生态应用场景。在基于以上两个基础平台,实现区块链生态体系的构建。而到目前为止,基于1+1+N的ATC落地可行性方案已经确认,产品设计已经基本完成。计划八月底中下旬出第一个版本App。同理,法律、产品信用、扶贫、CROS BANK项目的业务场景梳理清楚后,基于基础平台可以快速复制落地,下半年各种生态应用将逐步落地。有了CROS和WBC这两个平台,我们可以很方便的就帮助任商家自建(CROS)或者映射(WBC)的方式一步跨进区块链世界,实现N种生态化的商业运作。发布于 2018-07-30 14:50区块链(Blockchain)通证经济​赞同​​1 条评论​分享​喜欢​收藏​申请

一文弄懂 CORS 跨域(前端+后端代码实例讲解) - 知乎

一文弄懂 CORS 跨域(前端+后端代码实例讲解) - 知乎切换模式写文章登录/注册一文弄懂 CORS 跨域(前端+后端代码实例讲解)茉莉蜜茶only空白以前经常被问到一些问题,比如写 Java 服务端的同学的来问:我服务端明明正确返回了,测试环境 debug 能看到,为什么前端就是拿不到数据? 然后写前端的同学会问:为什么我明明设置了 withCredentials=true,服务端同学还是拿不到 cookie?所以决定重新捋一捋使用 CORS 解决跨域的问题,前后端要怎么做?为什么这么做?为什么会有跨域的问题?为了保证用户信息的安全,所有的浏览器都遵循同源策略,那什么情况下算同源呢?同源策略又是什么呢? 记住:协议、域名、端口号完全相同时,才是同源可以参考 Web安全 - 浏览器的同源策略在同源策略下,会有以下限制:无法获取非同源的 Cookie、LocalStorage、SessionStorage 等无法获取非同源的 dom无法向非同源的服务器发送 ajax 请求但是我们又经常会遇到前后端分离,不在同一个域名下,需要ajax请求数据的情况。那我们就要规避这种限制。 可以在网上搜到很多解决跨域的方法,有些方法比较古老了,现在项目中用的比较多的是 jsonp 和 CORS(跨域资源共享),这篇主要讲 CORS 的原理和具体实践。CORS 跨域原理CORS 跨域的原理实际上是浏览器与服务器通过一些 HTTP 协议头来做一些约定和限制。可以查看 HTTP-访问控制(CORS)与跨域相关的协议头 代码实例这里写了个 demo,一步步来分析。目录如下:.

├── README.md

├── client

│ ├── index.html

│ └── request.js

└── server

├── pom.xml

├── server-web

│ ├── pom.xml

│ ├── server-web.iml

│ └── src

│ └── main

│ ├── java

│ │ └── com

│ │ └── example

│ │ └── cors

│ │ ├── constant

│ │ │ └── Constants.java

│ │ ├── controller

│ │ │ └── CorsController.java

│ │ └── filter

│ │ └── CrossDomainFilter.java

│ ├── resources

│ │ └── config

│ │ └── applicationContext-core.xml

│ └── webapp

│ ├── WEB-INF

│ │ ├── dispatcher-servlet.xml

│ │ └── web.xml

│ └── index.jsp

└── server.imlClient:前端,简单的ajax请求 在client文件夹下,启动静态服务器,前端页面通过http://localhost:8000/index.html访问:anywhere -h localhost -p 8000Server: java项目,SpringMVC在 IntelliJ IDEA 中本地启动 tomcat,设置host: http://localhost:8080/,服务端数据通过http://localhost:8080/server/cors请求。这里前端和后端因为端口号不同,存在跨域限制,下面通过 CORS 来解决因为跨域无法通过ajax请求数据的问题。没有允许跨域的情况这种情况就是前端什么都不做,服务端也什么都不做。Client: 请求成功后,将数据显示在页面上new Request().send('http://localhost:8080/server/cors',{

success: function(data){

document.write(data)

}

});

Server:@Controller

@RequestMapping("/server")

public class CorsController {

@RequestMapping(value="/cors", method= RequestMethod.GET)

@ResponseBody

public String ajaxCors(HttpServletRequest request) throws Exception{

return "SUCCESS";

}

}在浏览器地址栏输入http://localhost:8080/server/cors直接请求服务端,可以看到返回结果: ‘SUCCESS’在浏览器地址栏输入http://localhost:8000/index.html,从不同域的网页中向 Server 发送 ajax 请求。可以看到几个方面:从 network 可以看到,请求返回正常。但 Response 中没有内容,显示 Failed to load response data。并且控制台报错:总结: 浏览器请求是发出去了的,服务端也会正确返回,但是我们拿不到response的内容浏览器控制台会报错提示可以怎么做,而且提示的很明白: xhr不能请求http://localhost:8080/server/cors,请求资源的响应头中没有设置Access-Control-Allow-Origin,Origin:http://localhost:8000是不允许跨域请求的。那下一步,我们要在服务端响应跨域请求时,设置响应头: Access-Control-Allow-Origin设置 Access-Control-Allow-Origin 允许跨域先说明为什么要设置 Access-Control-Allow-Origin,可以把 Access-Control-Allow-Origin 当作一个指令,服务端设置 Access-Control-Allow-Origin 就是告诉浏览器允许向服务端请求资源的域名,浏览器通过 Response 中的 Access-Control-Allow-Origin 就可以知道能不能把数据吐出来。官方解释是这样的: Access-Control-Allow-Origin 响应头指定了该响应的资源是否被允许与给定的 origin 共享。Access-Control-Allow-Origin可以设置的值有:Access-Control-Allow-Origin: *

Access-Control-Allow-Origin:那在java服务端给响应头设置 Access-Control-Allow-Origin 可以这么做:1、添加一个过滤器public class CrossDomainFilter implements Filter{

public void init(FilterConfig filterConfig) throws ServletException {}

public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

HttpServletResponse resp = (HttpServletResponse)servletResponse;

resp.setHeader("Access-Control-Allow-Origin", "http://localhost:8000");

filterChain.doFilter(servletRequest,servletResponse);

}

public void destroy() {}

}2、然后在web.xml文件中添加过滤器配置:

crossDomainFilter

com.example.cors.filter.CrossDomainFilter

crossDomainFilter

/*

3、然后重新启动tomcat,client重新发送请求http://localhost:8000/index.html 可以看到我们能够拿到返回结果了,响应头中有我们在服务端设置的Access-Control-Allow-Origin: http://localhost:8000,这个应该跟请求头中的origin一致,或者设置Access-Control-Allow-Origin:*也是可以的,这就允许任何网站来访问资源了(前提是不带凭证信息,这个后面讲)以上就是允许一个简单的跨域请求的做法,只需要服务端设置响应头Access-Control-Allow-Origin。 简单请求与预检请求上面讲述了一个简单请求通过在服务端设置响应头 Access-Control-Allow-Origin 就可以完成跨域请求。那怎样的请求算是一个简单请求?与简单请求相对应的是什么样的请求呢?解决跨域的方式又有什么不一样呢?符合以下条件的可视为简单请求:1、使用下列 HTTP 方法之一- GET

- HEAD

- POST,并且Content-Type的值在下列之一:

- text/plain

- multipart/form-data

- application/x-www-form-urlencoded2、并且请求头中只有下面这些- Accept

- Accept-Language

- Content-Language

- Content-Type (需要注意额外的限制)

- DPR

- Downlink

- Save-Data

- Viewport-Width

- Width不满足上述要求的在发送正式请求前都要先发送一个预检请求,预检请求以 OPTIONS 方法发送,浏览器通过请求方法和请求头能够判断是否发送预检请求。比如 Client 发送如下请求:new Request().send('http://localhost:8080/server/options',{

method: 'POST',

header: {

'Content-Type': 'application/json' //告诉服务器实际发送的数据类型

},

success: function(data){

document.write(data)

}

});

Server 端处理请求的 controller:@Controller

@RequestMapping("/server")

public class CorsController {

@RequestMapping(value="/options", method= RequestMethod.POST)

@ResponseBody

public String options(HttpServletRequest request) throws Exception{

return "SUCCESS";

}

}因为请求时,请求头中塞入了 header,'Content-Type': 'application/json'。根据前面讲述的可以知道,浏览器会以 OPTIONS 方法发出一个预检请求,浏览器会在请求头中加入:Access-Control-Request-Headers:content-type

Access-Control-Request-Method:POST这个预检请求的作用在这里就是告诉服务器:我会在后面请求的请求头中以 POST 方法发送数据类型是application/json 的请求,询问服务器是否允许。在这里服务器还没有做任何允许这种请求的设置,所以浏览器控制台报错:也清楚的说明了出错的原因: 服务端在预检请求的响应中没有告诉浏览器允许协议头 Content-Type,即服务端需要设置响应头 Access-Control-Allow-Headers,允许浏览器发送带 Content-Type 的请求。Server端过滤器中添加Access-Control-Allow-Headers:public class CrossDomainFilter implements Filter{

public void init(FilterConfig filterConfig) throws ServletException {}

public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

HttpServletResponse resp = (HttpServletResponse)servletResponse;

resp.setHeader("Access-Control-Allow-Origin", "http://localhost:8000");

resp.setHeader("Access-Control-Allow-Headers", "Content-Type");

filterChain.doFilter(servletRequest,servletResponse);

}

public void destroy() {}

}可以看到请求成功再来看请求的具体信息,第一次以 OPTIONS 方法发送预检请求,浏览器设置请求头:Access-Control-Request-Headers:content-type //请求中加入的请求头

Access-Control-Request-Method:POST //跨域请求的方法服务端设置响应头:Access-Control-Allow-Headers:Content-Type //允许的header

Access-Control-Allow-Origin:http://localhost:8000 //允许跨域的源也可以设置 Access-Control-Allow-Methods 来限制客户端的的请求方法。这样预检请求成功了,浏览器会发出第二个请求,这是真正请求数据的请求:可以看到 POST 请求成功了,第二次请求头中没有设置 Access-Control-Request-Headers 和 Access-Control-Request-Method。但是这里有个问题,需要预检请求时,浏览器会发出两次请求,一次 OPTIONS,一次 POST。两次都返回了数据。这样服务端如果逻辑复杂一些,比如去数据库查找数据,从 web 层、 service 到数据库这段逻辑就会走两遍,浏览器会两次拿到相同的数据,所以服务端的 filter 可以改一下,如果是 OPTIONS 请求,在设置完跨域请求响应头后就不走后面的逻辑直接返回。public class CrossDomainFilter implements Filter{

public void init(FilterConfig filterConfig) throws ServletException {}

public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

HttpServletResponse resp = (HttpServletResponse)servletResponse;

resp.setHeader("Access-Control-Allow-Origin", "http://localhost:8000");

resp.setHeader("Access-Control-Allow-Headers", "Content-Type");

//OPTION请求就直接返回

HttpServletRequest req = (HttpServletRequest) servletRequest;

if (req.getMethod().equals("OPTIONS")) {

resp.setStatus(200);

resp.flushBuffer();

}else {

filterChain.doFilter(servletRequest,servletResponse);

}

}

public void destroy() {}

}总结: **对于POST请求设置响应头Content-Type为某些值、自定义请求头等情况,浏览器会先以OPTIONS方法发送一个预检请求,并设置相应的请求头。服务端还是正常返回,但如果预检请求响应头中不设置相应的响应头,预检请求不通过,不会再发出第二次请求来获取数据。服务端设置相应的响应头,浏览器会发出第二个请求,并将服务端返回的数据吐出,我们可以获得response的内容带凭证信息的请求还有一种情况我们经常遇到。浏览器在发送请求时需要给服务端发送 cookie,服务端根据 cookie 中的信息做一些身份验证等。默认情况下,浏览器向不同域的发送 ajax 请求,不会携带发送 cookie 信息。Client:var containerElem = document.getElementById('container')

new Request().send('http://localhost:8080/server/testCookie',{

success: function(data){

containerElem.innerHTML = data

}

});

Server:@RequestMapping(value="/testCookie", method= RequestMethod.GET)

@ResponseBody

public String testCookie(HttpServletRequest request,HttpServletResponse response) throws Exception{

String str = "SUCCESS";

Cookie[] cookies = request.getCookies();

String school = getSchool(cookies);

if(school == null || school.length() == 0){

addCookie(response);

}

return str + buildText(cookies);

}服务端收到请求,判断 cookie 中有没有 school,没有就添加 cookie.可以看到响应头中有 Set-Cookie,再次请求时,如果是同源请求,浏览器会将 Set-Cookie 中的值放在请求头中,但是对于跨域请求,默认是不发送这个 Cookie 的。如果要让浏览器发送 cookie,需要在 Client 设置 XMLHttpRequest 的 withCredentials 属性为 true。Client:var containerElem = document.getElementById('container')

new Request().send('http://localhost:8080/server/testCookie',{

withCredentials: true,

success: function(data){

containerElem.innerHTML = data

}

});

现在浏览器在请求头中加入了 cookie 信息但是服务端返回的数据没有在页面中展示,并且报错:报错信息很明白: 当请求中包含凭证信息时,需要设置响应头 Access-Control-Allow-Credentials,是否带凭证信息是由 XMLHttpRequest的withCredentials 属性控制的。 ** 所以我们在 Server 端 filter 中加入这个响应头:public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

HttpServletResponse resp = (HttpServletResponse)servletResponse;

resp.setHeader("Access-Control-Allow-Origin", "http://localhost:8000");

resp.setHeader("Access-Control-Allow-Credentials","true");

HttpServletRequest req = (HttpServletRequest) servletRequest;

if (req.getMethod().equals("OPTIONS")) {

resp.setStatus(200);

resp.flushBuffer();

}else {

filterChain.doFilter(servletRequest,servletResponse);

}

}现在浏览器知道响应头中 Access-Control-Allow-Credentials 为 true,就会把数据给吐出来了,我们能够从response 中拿到内容了。那如果附带凭证信息并且有预检请求呢?如果有预检请求,并附带凭证信息( XMLHttpRequest 的withCredentials 设置为 true), 服务端需要设置 Access-Control-Allow-Credentials: true,否则浏览器不会发出第二次请求,并报错。总结: 跨域请求时,浏览器默认不会发送cookie,需要设置XMLHttpRequest的withCredentials属性为true浏览器设置XMLHttpRequest的withCredentials属性为true,表明要向服务端发送凭证信息(这里是cookie)。那么服务端就需要在响应头中添加Access-Control-Allow-Credentials为true。否则浏览器上有两种情况:如果是简单请求,服务端结果吐出了,浏览器拿到了但就是不给吐出来,并报错。如果是预检请求,同样我们拿不到返回结果,并报错提示预检请求不通过,不会再发第二次请求。其他cookie 的同源策略另外就是设置了 XMLHttpRequest 的 withCredentials 属性为 true,浏览器发出去了,服务端还是拿不到 cookie的问题。cookie 也遵循同源策略的,在设置 cookie 的时候可以发现除了键值对,还可以设置 cookie 的这些值:如果获取不到 cookie,可以检查下 cookie 的 domain 和 path.IE 上跨域访问没有权限在跨域发送 ajax 请求时提示没有权限。 因为IE浏览器默认对跨域访问有限制。需要在浏览器设置中去除限制。 方法: 设置 > Internet 选项 > 安全 > 自定义级别 > 在设置中找到其他 - 在【其他】中将【通过域访问数据源】启用。Demo 源码CORS Demo 源码参考Web安全 - 浏览器的同源策略HTTP-访问控制(CORS)Document - Document.cookie聊一聊 cookie编辑于 2020-05-11 19:57Web 开发跨域​赞同 54​​5 条评论​分享​喜欢​收藏​申请

跨域——CORS详解 - 知乎

跨域——CORS详解 - 知乎切换模式写文章登录/注册跨域——CORS详解二流程序猿CORS(Cross-origin resource sharing) “跨域资源共享” 在出现CORS标准之前, 我们还只能通过jsonp(jsonp跨域请求详解)的形式去向“跨源”服务器去发送 XMLHttpRequest 请求,这种方式吃力不讨好,在请求方与接收方都需要做处理,而且请求的方式仅仅局限于GET。所以 ,CORS标准必然是大势所趋,并且市场上绝大多数浏览器都已经支持CORS。(IE10以上)CORS概念支持CORS请求的浏览器一旦发现ajax请求跨域,会对请求做一些特殊处理,对于已经实现CORS接口的服务端,接受请求,并做出回应。有一种情况比较特殊,如果我们发送的跨域请求为“非简单请求”,浏览器会在发出此请求之前首先发送一个请求类型为OPTIONS的“预检请求”,验证请求源是否为服务端允许源,这些对于开发这来说是感觉不到的,由浏览器代理。总而言之,客户端不需要对跨域请求做任何特殊处理。简单请求与非简单请求浏览器对跨域请求区分为“简单请求”与“非简单请求”“简单请求”满足以下特征:(1) 请求方法是以下三种方法之一:

HEAD

GET

POST

(2)HTTP的头信息不超出以下几种字段:

Accept

Accept-Language

Content-Language

Last-Event-ID

Content-Type:

application/x-www-form-urlencoded、 multipart/form-data、text/plain不满足这些特征的请求称为“非简单请求”,例如:content-type=applicaiton/json , method = PUT/DELETE...简单请求浏览器判断跨域为简单请求时候,会在Request Header中添加 Origin (协议 + 域名 + 端口)字段 , 它表示我们的请求源,CORS服务端会将该字段作为跨源标志。CORS接收到此次请求后 , 首先会判断Origin是否在允许源(由服务端决定)范围之内,如果验证通过,服务端会在Response Header 添加 Access-Control-Allow-Origin、Access-Control-Allow-Credentials等字段。必须字段:

Access-Control-Allow-Origin:表示服务端允许的请求源,*标识任何外域,多个源 , 分隔

可选字段

Access-Control-Allow-Credentials:false 表示是否允许发送Cookie,设置为true

同时,ajax请求设置withCredentials = true,浏览

器的cookie就能发送到服务端

Access-Control-Expose-Headers:调用getResponseHeader()方法时候,能从header中获

取的参数

浏览器收到Respnose后会判断自己的源是否存在 Access-Control-Allow-Origin允许源中,如果不存在,会抛出“同源检测异常”。总结:简单请求只需要CORS服务端在接受到携带Origin字段的跨域请求后,在response header中添加Access-Control-Allow-Origin等字段给浏览器做同源判断。非简单请求进行非简单请求时候 , 浏览器会首先发出类型为OPTIONS的“预检请求”,请求地址相同 , CORS服务端对“预检请求”处理,并对Response Header添加验证字段,客户端接受到预检请求的返回值进行一次请求预判断,验证通过后,主请求发起。例如:发起 content-type=application/json 的非简单请求,这时候传参要注意为json字符串这里可以看到,浏览器连续发送了两个jsonp.do请求 , 第一个就是“预检请求”,类型为OPTIONS,因为我们设置了content-type这个属性,所以预检请求的Access-Control-Expose-Headers必须携带content-type,否则预检会失败。预检通过后,主请求与简单请求一致。总结:非简单请求需要CORS服务端对OPTIONS类型的请求做处理,其他与简单请求一致Spring MVC CORS通过上面叙述,我们得知借助CORS我们不必关心发出的请求是否跨域,浏览器会帮我们处理这些事情,但是服务端需要支持CORS,服务端实现CORS的原理也很简单,在服务端完全可以对请求做上下文处理,已达到接口允许跨域访问的目的。当然,也有很多第三方的CORS插件,例如:Spring MVC 在4.2以上版本也支持了CORS配置,这样,服务端也无需自己操心了!相关文档跨域资源共享 CORS 详解 - 阮一峰的网络日志SpringMvc解决跨域问题 - 王念博客 - 开源中国社区发布于 2016-12-17 14:05SpringAjaxHTTP​赞同 110​​7 条评论​分享​喜欢​收藏​申请

CROS 跨域请求原理-CSDN博客

>

CROS 跨域请求原理-CSDN博客

CROS 跨域请求原理

最新推荐文章于 2023-10-19 11:42:02 发布

qq_36416878

最新推荐文章于 2023-10-19 11:42:02 发布

阅读量6.8k

收藏

4

点赞数

1

分类专栏:

面试

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

本文链接:https://blog.csdn.net/qq_36416878/article/details/109031995

版权

面试

专栏收录该内容

4 篇文章

0 订阅

订阅专栏

cros 分为两种请求

简单请求

浏览器将CORS请求分成两类:简单请求(simple request)和非简单请求(预检请求)(not-so-simple request)。

只要同时满足以下两大条件,就属于简单请求。

(1) 请求方法是以下三种方法之一:

HEAD

GET

POST

(2)HTTP请求头信息不超出以下几种字段:

Accept

Accept-Language

Content-Language

Last-Event-ID

Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain

凡是不同时满足上面两个条件,就属于非简单请求。

浏览器对这两种请求的处理,是不一样的。

Access-Control-Allow-Origin: http://kbiao.me Access-Control-Max-Age: 3628800 Access-Control-Allow-methods: GET, PUT, DELETE, POST Access-Control-Allow-Header: content-type Access-Control-Allow-Credentail: true

“Access-Control-Allow-Origin"表明它允许” http://kbiao.me "发起跨域请求

"Access-Control-Max-Age"表明在3628800秒内,不需要再发送预检验请求,可以缓存该结果(上面的资料上我们知道CROS协议中,一个AJAX请求被分成了第一步的OPTION预检测请求和正式请求)

"Access-Control-Allow-Methods"表明它允许GET、PUT、DELETE的外域请求

"Access-Control-Allow-Headers"表明它允许跨域请求包含content-type头

"Access-Control-Allow-Credentials"表明它允许cookies

优惠劵

qq_36416878

关注

关注

1

点赞

4

收藏

觉得还不错?

一键收藏

知道了

0

评论

CROS 跨域请求原理

cros 分为两种请求简单请求浏览器将CORS请求分成两类:简单请求(simple request)和非简单请求(预检请求)(not-so-simple request)。只要同时满足以下两大条件,就属于简单请求。(1) 请求方法是以下三种方法之一:HEADGETPOST(2)HTTP请求头信息不超出以下几种字段:AcceptAccept-LanguageContent-LanguageLast-Event-IDContent-Type:只限于三个值applicat

复制链接

扫一扫

专栏目录

layui-table-cros:layui表格跨域请求

02-21

layui-table-cros:layui表格跨域请求

cros更新

02-25

Chrome操作系统更新

该存储库托管 ,这是我正在构建的网站,用于替换著名的 appspot应用程序。 该存储库由两部分组成:

网页抓取脚本

位于/scripts是一个节点脚本,Github Actions每15分钟运行一次,以为其数据服务。 如果您知道一个更好的位置来获取特定于主板的Chrome操作系统版本数据,请提出一个问题。

静态网络应用

存储库的其余部分是一个基于的Web应用程序,以一种更加用户友好的方式显示版本数据。 在推送到master时, 会静态呈现页面。 有计划将网站构建过程移至Github Actions,以节省Netlify构建时间。

报告问题

如果您在网站上遇到问题,请在存储库中,并提供有关该问题的尽可能多的信息。 如果您至少可以提供设备类型和操作系统/浏览器版本,那就太好了。

其他注意事项

由于版本数据以JSON格式存储在Git中,因此该存储库可以用作最近7个月

参与评论

您还未登录,请先

登录

后发表或查看评论

CROS错误 网络跨域

weixin_51689532的博客

06-19

635

CROS错误 网络出现跨域的几种情况

服务端跨域处理原理以及处理

bjrxyz的专栏

01-30

659

随着CROS标准的推广,跨域成了每个服务器开发者必须处理的问题,网上关于如何解决跨域问题的文章数不胜数,但是能用的少之又少,不少文章作者都不清楚跨域原理,不知从哪里抄来一字半句发现有效果就匆匆发表,误导了不知多少人。其实处理跨域的原理并不复杂,本文会介绍处理跨域的原理并给出python实现。

cros 相关的知识总结

weixin_30877181的博客

11-09

450

一,百度百科相关的介绍:

随着GPS技术的飞速进步和应用普及,它在城市测量中的作用已越来越重要。当前,利用多基站网络RTK技术建立的连续运行(卫星定位服务)参考站(Continuously Operating Reference Stations),缩写为CORS)已成为城市GPS应用的发展热点之一。CORS系统是卫星定位技术、计算机网络技术、数字通讯技术等高新科技多方位、深度结晶的产物。 CO...

如何理解CROS

heroicpoem的专栏

07-09

3727

还沿用当初自己对这块的几个疑问,回答疑问的过程,也是梳理的过程。&:前后端分离的应用,前端、后端是2个独立的应用,运行在不同端口。在浏览器看来,是不同的域。前端页面中的ajax请求后端接口,即是跨域访问了,触发cros。&:有多种方法,其中1个是在后端应用设置允许放入的来访域请求。

对应的后端也支持了preflight(option)请求。

springboot有现成方法。eg:

3.浏览器是如何控制cros的?

&:浏览器对跨域请求,发出preflight;得到后端响应,看响应header中允许的来访域是

CORS 跨域解决方案

running_pork的博客

01-04

1763

复杂请求则需要2次,先发起options请求,确认目标资源是否支持跨域,浏览器会根据服务端响应的header自动处理剩余的请求,如果响应支持跨域,则继续发出正常请求;简单跨域请求只需要请求一次,复杂跨域请求需要请求2次,第一次是预检请求(options请求),第二次是真是的跨域请求。所以,当触发预检时,跨域请求便会发送2次请求,增加请求次数,同时,也延迟了请求真正发起的时间,会严重地影响性能。crossDomain: true //// 会让请求头中包含跨域的额外信息,但不会含cookie。

springboot之跨域访问cros,@CrossOrigin注解

YMYYZ的博客

01-09

7735

1.springboot之跨域访问cros,@CrossOrigin注解

2.浏览器协议的默认端口号

CROS 前后端交互,不可不知的跨域问题及其解决方案详解

FeelTouch Labs

10-19

231

在前后端不分离时,我们利用前面讲过的Spring Security的各种知识点,就可以实现对项目的权限管控。但是在前后端分离时,尤其是在引入了Spring Security后的前后端分离时,我们从前端发来的请求,就会存在一些问题。这些问题就是跨域而导致的问题!对于前后端分离时,跨域而产生的安全问题,我们该怎么解决呢?接下来请跟着一一哥来学习如何解决吧!在解决跨域问题之前,我们先来了解一下何为跨域问题,怎么产生的跨域问题,怎么解决这个跨域问题。CORS是一个W3C标准,全称是。

如何解决cros跨域问题

superioc的博客

03-30

448

跨域:指的是浏览器不能执行其他网站的脚本。它是由浏览器的同源策略造成的,是浏览器对javascript施加的安全限制。同源策略:是指协议,域名,端口都要相同,其中有一个不同都会产生跨域;具体来讲,同源策略(Same origin policy)是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。可以说Web是构建在同源策略基础之上的,浏览器只是针对同源策略的一种实现;

快速解决跨域请求问题:jsonp和CORS

10-18

主要介绍了快速解决跨域请求问题:jsonp和CORS,涉及jsonp和CORS的介绍,分享了前端 jQuery 写法,后端 SpringMVC 配置,后端非 SpringMVC 配置等相关内容,具有一定借鉴价值,需要的朋友可以参考下。

VUE axios发送跨域请求需要注意的问题

01-19

同理,跨域的解决方案为cros。服务器 PHP端代码如下(laravel 中间件进行处理): public function handle($request, Closure $next) { if ($request->isMethod('OPTIONS')) { $response = response('',

使用Spring CROS解决项目中的跨域问题详解

08-25

主要介绍了使用Spring CROS解决项目中的跨域问题详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

详解springboot设置cors跨域请求的两种方式

08-26

主要介绍了详解springboot设置cors跨域请求的两种方式,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

springboot学生毕业离校系统PPT

最新发布

03-06

一年一度的毕业季的到来,方方面面都普及使得学生毕业离校系统的开发成为必需。学生毕业离校系统主要是借助计算机,通过对学生、教师、离校信息、费用结算、论文审核等信息进行管理。为减少管理员的工作,同时也方便广大学生对个人所需毕业离校的及时查询以及管理。

学生毕业离校系统的开发过程中,采用B / S架构,主要使用Java技术进行开发,结合最新流行的springboot框架。中间件服务器是Tomcat服务器,使用Mysql数据库和Eclipse开发环境。该学生毕业离校系统包括管理员、学生和教师。其主要功能包括管理员:首页、个人中心、学生管理、教师管理、离校信息管理、费用结算管理、论文审核管理、管理员管理、留言板管理、系统管理等,前台首页;首页、离校信息、网站公告、留言反馈、个人中心、后台管理等,学生:首页、个人中心、费用结算管理、论文审核管理、我的收藏管理、等,教师:首页、个人中心、学生管理、离校信息管理、费用结算管理、论文审核管理等功能。

本论文对学生毕业离校系统的发展背景进行详细的介绍,并且对系统开发技术进行介绍,然后对系统进行需求分析,对学生毕业离校系统业务信息、系统结构以及数据都进行详细

Java毕设-基于SpringBoot+Vue的宠物商城网站设计与实现(附源码,数据库,教程).zip

03-06

Java 毕业设计,Java 课程设计,基于 SpringBoot 开发的,含有代码注释,新手也可看懂。毕业设计、期末大作业、课程设计、高分必看,下载下来,简单部署,就可以使用。

包含:项目源码、数据库脚本、软件工具等,前后端代码都在里面。

该系统功能完善、界面美观、操作简单、功能齐全、管理便捷,具有很高的实际应用价值。

项目都经过严格调试,确保可以运行!

1. 技术组成

前端:html、javascript、Vue

后台框架:SpringBoot

开发环境:idea

数据库:MySql(建议用 5.7 版本,8.0 有时候会有坑)

数据库工具:navicat

部署环境:Tomcat(建议用 7.x 或者 8.x 版本), maven

2. 部署

如果部署有疑问的话,可以找我咨询

后台路径地址:localhost:8080/项目名称/admin/dist/index.html

前台路径地址:localhost:8080/项目名称/front/index.html (无前台不需要输入)

财富管理系统,全球前10强生产商排名及市场份额调研数据.pdf

03-06

财富管理系统,全球前10强生产商排名及市场份额调研数据

springboot139基于SpringBoot华强北商城二手手机管理系统-毕业源码案例设计

03-06

进入21世纪网络和计算机得到了飞速发展,并和生活进行了紧密的结合。目前,网络的运行速度以达到了千兆,覆盖范围更是深入到生活中的角角落落。这就促使二手交易网站的发展。二手交易网站可以实现远程购物,远程选择喜欢的商品和随时追踪订单的状态。二手交易网站给人们带来前所未有的体验,满足了新时代人们的购物需求,所以网上二手交易模式得到大力发展。

本系统为基于Springboot的华强北商城二手手机管理系统,是采用计算机和网络技术进行开发的在线交易平台,可以实现商品的展示、购买、评价以及销售等。本系统采用Java语言,数据库为Mysql,运行环境为Idea。使用角色分为注册用户、游客、管理员、商家,本系统的功能包括新闻管理、商品信息展示以及管理、注册用户管理、订单管理、商品评价同时还可以管理购物车。其中,游客负责浏览信息,注册用户可以购买商品、评价商品、管理订单,商家可以销售商品管理订单,管理员可以管理所有功能以及个人信息。本系统实现了商品的在线销售与购买,方便了购买者和销售者双方的利益,提高销量和购买效率,更符合现代人生活。

关键词:购物车,用户注册,商品信息管理,订单管理,Java语言

c语言文件读写操作代码

03-06

c语言文件读写操作代码

php cros

05-31

CORS (Cross-Origin Resource Sharing) 是一种安全机制,用于限制跨域请求。在 PHP 中,可以通过设置响应头来控制 CORS,例如: ```php header('Access-Control-Allow-Origin: *'); // 允许所有来源访问 header('...

“相关推荐”对你有帮助么?

非常没帮助

没帮助

一般

有帮助

非常有帮助

提交

qq_36416878

CSDN认证博客专家

CSDN认证企业博客

码龄7年

暂无认证

21

原创

76万+

周排名

201万+

总排名

5万+

访问

等级

699

积分

4

粉丝

7

获赞

4

评论

31

收藏

私信

关注

分类专栏

面试

4篇

js

3篇

vue

16篇

es6

6篇

webpack

4篇

最新评论

es6 const定义基本数据类型的变量是不可以修改,其它复杂数据类型是可以修改的

Guaners:

012吗不是

artTemplate 模板引擎 添加自定义函数方法

卡车z:

多个参数怎么办

es6 const定义基本数据类型的变量是不可以修改,其它复杂数据类型是可以修改的

就想起个不一样的名字:

确定arr[3]有值吗

记录vue项目中使用better-scroll插件实现滚动点击失效的问题

慷慨悲歌:

感谢,找了半天原来是因为这个

您愿意向朋友推荐“博客详情页”吗?

强烈不推荐

不推荐

一般般

推荐

强烈推荐

提交

最新文章

http1.1 和 http2 区别 缓存

js es5 和es6 的继承

typeof instanceof 区别

2020年8篇

2019年1篇

2018年35篇

目录

目录

分类专栏

面试

4篇

js

3篇

vue

16篇

es6

6篇

webpack

4篇

目录

评论

被折叠的  条评论

为什么被折叠?

到【灌水乐园】发言

查看更多评论

添加红包

祝福语

请填写红包祝福语或标题

红包数量

红包个数最小为10个

红包总金额

红包金额最低5元

余额支付

当前余额3.43元

前往充值 >

需支付:10.00元

取消

确定

下一步

知道了

成就一亿技术人!

领取后你会自动成为博主和红包主的粉丝

规则

hope_wisdom 发出的红包

实付元

使用余额支付

点击重新获取

扫码支付

钱包余额

0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。 2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值