이 기사에서는 CORS를 사용하여 도메인 간 Ajax 요청을 완료하는 Koa2 프레임워크를 주로 소개하고 참고용으로 제공합니다.
교차 도메인 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입니다. 요청에 성공적으로 응답할 수 있는지 여부입니다.
서버에서 이 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 요청에 응답할 수 있지만 이 도메인 아래의 쿠키는 요청 헤더에 전달되지 않습니다. 쿠키를 서버로 가져오고 서버가 쿠키를 추가로 설정하도록 허용하려면 추가 구성이 필요합니다.
후속 감지를 용이하게 하기 위해 도메인 이름 http://127.0.0.1:3001에 두 개의 쿠키를 미리 설정합니다. 실수로 쿠키를 중국어로 설정하지 않도록 주의하세요. (그냥 중국어로 설정했는데 결과가 에러가 나더군요. 오랫동안 에러의 원인을 찾지 못했습니다.)
그러면 2단계를 해야 합니다. 첫 번째 단계는 응답 헤더 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(); });
这样就减少了多余的响应头。
上面是我整理给大家的,希望今后会对大家有帮助。
相关文章:
위 내용은 Koa2 프레임워크를 통해 CORS를 사용하여 도메인 간 Ajax 요청을 구현하는 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!