이번에는 Koa2 프레임워크의 CORS를 사용하여 Cross-domain Ajax 요청을 완료하는 방법을 보여드리겠습니다. Koa2 프레임워크의 CORS를 사용하여 Cross-domain Ajax 요청을 완료할 때 주의해야 할 주의사항은 무엇인가요? 다음은 실제 사례입니다. 살펴보겠습니다.
교차 도메인 Ajax 요청을 구현하는 방법에는 여러 가지가 있으며 그 중 하나는 CORS를 사용하는 것이며 이 방법의 핵심은 서버 측에서 구성하는 것입니다.
이 글에서는 일반적인 크로스 도메인 Ajax 응답을 완료할 수 있는 가장 기본적인 구성만 설명합니다. (자세한 구성은 어떻게 해야할지 모르겠습니다.)
CORS는 요청을 단순 요청과 비단순 요청으로 구분합니다. 추가 요청 헤더 없이 단순 요청은 get 및 post 요청이라고 간단히 생각할 수 있으며, post 요청인 경우 요청 형식은 application/json이 될 수 없습니다. (저는 이 부분에 대한 깊은 이해가 없기 때문에. 만약 실수가 있다면 누군가가 실수를 지적하고 수정을 제안해줬으면 좋겠습니다.) 나머지 요청, Put 및 Post 요청, Content-Type application/json을 사용한 요청, 사용자 정의 요청 헤더가 있는 요청은 단순하지 않은 요청입니다.
단순 요청의 구성은 매우 간단합니다. 목표를 달성하기 위해 응답만 완료하면 되는 경우 응답 헤더에 Access-Control-Allow-Origin만 구성하면 됩니다.
http://localhost:3000 도메인 이름 아래의 http://127.0.0.1:3001 도메인 이름에 액세스하려는 경우. 다음과 같이 구성할 수 있습니다.
app.use(async (ctx, next) => { ctx.set('Access-Control-Allow-Origin', 'http://localhost:3000'); await next(); });
그런 다음 ajax를 사용하여 게시 요청과 같은 간단한 요청을 시작하면 서버에서 올바른 응답을 쉽게 얻을 수 있습니다.
실험 코드는 다음과 같습니다.
$.ajax({ type: 'post', url: 'http://127.0.0.1:3001/async-post' }).done(data => { console.log(data); })
서버측 코드:
router.post('/async-post',async ctx => { ctx.body = { code: "1", msg: "succ" } });
그러면 올바른 응답 정보를 얻을 수 있습니다.
이때 요청과 응답의 헤더 정보를 보면 요청 헤더에 추가적인 출처가 있고(요청의 URL 주소에 대한 리퍼러도 있음) 응답 헤더에는 추가 액세스 제어-허용-원점.
이제 간단한 요청을 보낼 수 있지만 단순하지 않은 요청을 보내려면 여전히 다른 구성이 필요합니다.
비단순 요청이 처음으로 발행되면 두 개의 요청이 발행됩니다. 첫 번째 요청은 이 요청의 요청 방법에 따라 이 요청의 통과 여부가 결정됩니다. 단순하지 않은 요청에 성공적으로 응답할 수 있는지 여부입니다.
서버에서 이 OPTIONS 유형 요청을 일치시키려면 이에 맞는 미들웨어를 만들고 사전 검사를 통과할 수 있도록 응답해야 합니다.
app.use(async (ctx, next) => { if (ctx.method === 'OPTIONS') { ctx.body = ''; } await next(); });
이렇게 하면 OPTIONS 요청이 전달될 수 있습니다.
실행 전 요청의 요청 헤더를 확인하면 요청 헤더가 두 개 더 있다는 것을 알 수 있습니다.
Access-Control-Request-Method: PUT Origin: http://localhost:3000
이 두 헤더 정보를 통해 서버와 협상하여 서버 응답 조건을 충족하는지 확인하세요.
이해하기 쉽습니다. 요청 헤더에는 두 가지 정보가 더 있으므로 응답 헤더에는 당연히 해당하는 두 가지 정보가 있어야 합니다.
Access-Control-Allow-Origin: http://localhost:3000 Access-Control-Allow-Methods: PUT,DELETE,POST,GET
첫 번째 정보는 동일합니다. 원산지이므로 통과합니다. 두 번째 정보는 Access-Controll-Request-Method에 해당합니다. 서버에서 허용하는 응답 방법에 요청 방법이 포함되어 있으면 이 정보도 통과됩니다. 두 제약 조건이 모두 충족되므로 요청이 성공적으로 시작될 수 있습니다.
지금까지는 사전 확인만 완료하고 실제 요청을 보내지 않은 것과 같습니다.
물론 실제 요청도 응답을 성공적으로 받았고, 응답 헤더는 다음과 같습니다(중요하지 않은 부분 생략)
Access-Control-Allow-Origin: http://localhost:3000 Access-Control-Allow-Methods: PUT,DELETE,POST,GET
요청 헤더는 다음과 같습니다.
Origin: http://localhost:3000
이것은 매우 명백합니다. 응답 헤더 정보는 다음과 같이 설정됩니다. 우리는 서버에 있습니다. 그렇습니다.
클라이언트는 Access-Control-Request-Method 요청 헤더가 지금 미리 확인되었기 때문에 보낼 필요가 없습니다.
이 예제의 코드는 다음과 같습니다.
$.ajax({ type: 'put', url: 'http://127.0.0.1:3001/put' }).done(data => { console.log(data); });
서버 코드:
app.use(async (ctx, next) => { ctx.set('Access-Control-Allow-Origin', 'http://localhost:3000'); ctx.set('Access-Control-Allow-Methods', 'PUT,DELETE,POST,GET'); await next(); });
이제 Cross-domain Ajax 응답을 올바르게 수행하기 위한 기본 구성이 완료되었으며, 추가로 구성할 수 있는 몇 가지 사항이 있습니다.
예를 들어, 지금까지 모든 단순하지 않은 요청은 실제로 실행 전 요청과 실제 요청이라는 두 개의 요청을 발행하므로 성능이 저하됩니다. 실행 전 요청을 보내지 않으려면 다음 응답 헤더를 구성할 수 있습니다.
Access-Control-Max-Age: 86400
这个响应头的意义在于,设置一个相对时间,在该非简单请求在服务器端通过检验的那一刻起,当流逝的时间的毫秒数不足Access-Control-Max-Age时,就不需要再进行预检,可以直接发送一次请求。
当然,简单请求时没有预检的,因此这条代码对简单请求没有意义。
目前代码如下:
app.use(async (ctx, next) => { ctx.set('Access-Control-Allow-Origin', 'http://localhost:3000'); ctx.set('Access-Control-Allow-Methods', 'PUT,DELETE,POST,GET'); ctx.set('Access-Control-Max-Age', 3600 * 24); await next(); });
到现在为止,可以对跨域ajax请求进行响应了,但是该域下的cookie不会被携带在请求头中。如果想要带着cookie到服务器,并且允许服务器对cookie进一步设置,还需要进行进一步的配置。
为了便于后续的检测,我们预先在http://127.0.0.1:3001这个域名下设置两个cookie。注意不要错误把cookie设置成中文(刚才我就设置成了中文,结果报错,半天没找到出错原因)
然后我们要做两步,第一步设置响应头Access-Control-Allow-Credentials为true,然后在客户端设置xhr对象的withCredentials属性为true。
客户端代码如下:
$.ajax({ type: 'put', url: 'http://127.0.0.1:3001/put', data: { name: '黄天浩', age: 20 }, xhrFields: { withCredentials: true } }).done(data => { console.log(data); });
服务端如下:
app.use(async (ctx, next) => { ctx.set('Access-Control-Allow-Origin', 'http://localhost:3000'); ctx.set('Access-Control-Allow-Methods', 'PUT,DELETE,POST,GET'); ctx.set('Access-Control-Allow-Credentials', true); await next(); });
这时就可以带着cookie到服务器了,并且服务器也可以对cookie进行改动。但是cookie仍是http://127.0.0.1:3001域名下的cookie,无论怎么操作都在该域名下,无法访问其他域名下的cookie。
现在为止CORS的基本功能已经都提到过了。
一开始我不知道怎么给Access-Control-Allow-Origin,后来经人提醒,发现可以写一个白名单数组,然后每次接到请求时判断origin是否在白名单数组中,然后动态的设置Access-Control-Allow-Origin,代码如下:
app.use(async (ctx, next) => { if (ctx.request.header.origin !== ctx.origin && whiteList.includes(ctx.request.header.origin)) { ctx.set('Access-Control-Allow-Origin', ctx.request.header.origin); ctx.set('Access-Control-Allow-Methods', 'PUT,DELETE,POST,GET'); ctx.set('Access-Control-Allow-Credentials', true); ctx.set('Access-Control-Max-Age', 3600 * 24); } await next(); });
这样就可以不用*通配符也可匹配多个origin了。
注意:ctx.origin与ctx.request.header.origin不同,ctx.origin是本服务器的域名,ctx.request.header.origin是发送请求的请求头部的origin,二者不要混淆。
最后,我们再稍微调整一下自定义的中间件的结构,防止每次请求都返回Access-Control-Allow-Methods以及Access-Control-Max-Age,这两个响应头其实是没有必要每次都返回的,只是第一次有预检的时候返回就可以了。
调整后顺序如下:
app.use(async (ctx, next) => { if (ctx.request.header.origin !== ctx.origin && whiteList.includes(ctx.request.header.origin)) { ctx.set('Access-Control-Allow-Origin', ctx.request.header.origin); ctx.set('Access-Control-Allow-Credentials', true); } await next(); }); app.use(async (ctx, next) => { if (ctx.method === 'OPTIONS') { ctx.set('Access-Control-Allow-Methods', 'PUT,DELETE,POST,GET'); ctx.set('Access-Control-Max-Age', 3600 * 24); ctx.body = ''; } await next(); });
这样就减少了多余的响应头。
相信看了本文案例你已经掌握了方法,更多精彩请关注php中文网其它相关文章!
推荐阅读:
위 내용은 Koa2 프레임워크의 CORS를 사용하여 도메인 간 Ajax 요청을 완료하는 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!