2016-08-11 1 views
4

Я запускаю HTTP-сервер с web :: http :: experimental :: listener :: http_listener из Microsoft C++ REST SDK 1.3.1 и пытаюсь написать HTML & Javascript как клиент для взаимодействия с сервером.Добавить Access-Control-Allow-Origin на http_listener в C++ REST SDK

почти без сюрприза Я получил ... Запрос на перекрестный запрос заблокирован: политика одного и того же происхождения запрещает читать удаленный ресурс в ...... (Причина: заголовок CORS 'Access-Control-Allow-Origin' отсутствует).

Как я могу положить Access-Control-Allow-Origin: * на стороне http listener (в коде C++)?

Возможно ли это в C++ REST 1.3.1 ?? есть обходное решение кроме JSONP?

Сервер

#include <cpprest/http_listener.h> 
#include <cpprest/json.h> 
using namespace web; 
using namespace web::http; 
using namespace web::http::experimental::listener; 

http_listener httpSrv; 
httpSrv->support(methods::GET, handle_get); 

void handle_get(http_request request) 
{ 
    const json::value response; 
    request.reply(status_codes::OK, response); 
} 

Клиент клиент с JQuery v1.12.4 (ограниченного с JQuery UI v1.12.0)

$("button").click(function() { 
     $.get(rest_url, function(data, status){ 
      console.log(status); 
      console.log(data); 
     }); 
    }); 

-------------- --- UPDATE -----------------------

Решение от ответа

SERVER

http_listener httpSrv; 
    httpSrv.support(methods::GET, handle_get); 
    httpSrv.support(methods::POST, handle_post); 
    httpSrv.support(methods::OPTIONS, handle_options); 
    httpSrv.open().wait(); 

    //........... 

    void handle_options(http_request request) 
    { 
    http_response response(status_codes::OK); 
    response.headers().add(U("Allow"), U("GET, POST, OPTIONS")); 
    response.headers().add(U("Access-Control-Allow-Origin"), U("*")); 
    response.headers().add(U("Access-Control-Allow-Methods"), U("GET, POST, OPTIONS")); 
    response.headers().add(U("Access-Control-Allow-Headers"), U("Content-Type")); 
    request.reply(response); 
    } 

    void handle_get(http_request request) 
    {   
    request.reply(status_codes::OK, ...); 
    } 

    void handle_post(http_request request) 
    { 
    json::value jsonResponse; 

    request 
     .extract_json() 
     .then([&jsonResponse](pplx::task<json::value> task) 
     { 
     jsonResponse = process_request(task.get()); 
     }) 
    .wait(); 

    http_response response(status_codes::OK); 
    response.headers().add(U("Access-Control-Allow-Origin"), U("*")); 
    response.set_body(jsonResponse); 
    request.reply(response); 
    } 

КЛИЕНТ

function requestREST(request/*json*/,onSuccess/*callback with json response*/) {  
    $.ajax({  
     type: "POST", 
     url: "...", 
     data: JSON.stringify(request), 
     dataType: 'json', 
     crossDomain: true, 
     contentType: "application/json", 
     success: function (response) { 
      onSuccess(response); 
     }, 
     timeout:3000, 
     statusCode: { 
      400: function (response) { 
       alert('Not working!'); 
      }, 
      0: function (response) { 
       alert('Not working!'); 
      }    
     } 
    }); 

ответ

3

Для добавления заголовков на стороне сервера (C++), вам необходимо изменить код, который вы используете, чтобы отправить ответ обратно.

На данный момент, вы используете:

request.reply(status_codes::OK, response); 

Вместо того, чтобы делать это в одной гильзе, идея заключается в том, чтобы составить ответ самостоятельно, начиная с пустой ответ, добавьте нужный заголовок, установите фактического тела, а затем отправить ответ клиенту.

Для конструирует пустой ответ, мы можем использовать следующую функцию:

web::http::http_response::http_response(http::status_code code) 

Как описано в the documentation, он создает ответ с заданным кодом состояния, без каких-либо заголовков и без тела.

Чтобы получить доступ к заголовкам ответа, мы можем использовать следующую функцию:

web::http::http_response::headers() 

Возвращаемый объект будет в http_headers type, который содержит add function:

web::http::http_headers::add(const key_type &name, const _t1 &value) 

Эта функция добавит заголовок ответа, если ему предоставлено имя и значение для заголовка.

Когда заголовок установлен, единственное, что осталось установить - это тело.Чтобы сделать это, ответ есть set_body function:

web::http::http_response::set_body(const json::value &body_data) 

В конце концов, полный код замены Однострочника создать пустой ответ, задайте заголовок и тело, а затем отправить его обратно будет выглядеть следующим образом:

http_response response(status_codes::OK); 
response.headers().add(U("Access-Control-Allow-Origin"), U("*")); 
response.set_body(jsonResponse); 
request.reply(response); 

Пожалуйста, обратите внимание, что в последней части кода, я использую U макрос для того, чтобы создать строку литерал целевого типа платформы. Вы можете найти более подробную информацию об этом U macro в C++ Rest SDK FAQ.

Что касается запросов на предварительную проверку с использованием HTTP-глагола OPTION, они ожидаются в такой ситуации. По умолчанию SDK C++ REST включает в себя реализацию по умолчанию для этих запросов. Реализация по умолчанию может быть проверена в the source code:

void details::http_listener_impl::handle_options(http_request message) 
{ 
    http_response response(status_codes::OK); 
    response.headers().add(U("Allow"), get_supported_methods()); 
    message.reply(response); 
} 

Это в основном возвращается 200 код статуса и добавить список поддерживаемых методов сервер может обрабатывать.

Если вы хотите переопределить реализацию по умолчанию, например, чтобы добавить некоторые конкретные заголовки, используемые предполетными запросы как Access-Control-Allow-Methods или Access-Control-Allow-Headers, вам нужно будет добавить определенный обработчик, как вы делали для GET и POST запросов с использованием:

web::http::experimental::listener::http_listener::support(const http::method &method, const std::function< void(http_request)> &handler) 

это не представляется возможным использовать общий обработчик для обработки OPTION запрос с:

web::http::experimental::listener::http_listener::support(const std::function<void(http_request)> &handler) 

причина, почему мы не можем использовать общий обработчик, если взглянуть на the source code, заключается в том, что если метод не имеет определенного обработчика и использует HTTP-глагол OPTION (или TRACE), обработчик по умолчанию, реализованный C++ REST SDK, будет можно называть:

// Specific method handler takes priority over general. 
const method &mtd = msg.method(); 
if(m_supported_methods.count(mtd)) 
{ 
    m_supported_methods[mtd](msg); 
} 
else if(mtd == methods::OPTIONS) 
{ 
    handle_options(msg); 
} 
+0

спасибо. см. UPDATE – elgcom

+0

Я отредактировал свой ответ, чтобы добавить сведения о предполетных запросах, которые являются точкой № 2 обновления. На самом деле не получилось очко №1. – HiDeo

+0

отлично. он работает просто отлично! – elgcom