В локальной сети между машинами, а также на одной машине в режиме отладки, делаю POST запросы XMLHttpRequest для выгрузки файла на второй сервер.
Со страницы https://xxx
(, где ключи и сертификат самоподписанные (уровня 1). Тестовый сервер Nginx, в продакшене будет другой, но там такие же ошибки.)
на сервер https://upserver:8888
(, где ключи и сертификаты самоподписанные (уровня 2, с использованием собственного центра сертификации, корневых, промежуточных и конечных сертификатов)
На порту 8888 работает Cowboy (Erlang/OTP v.23). Код с заголовками показан ниже.) Пока, там нет авторизации, а кросс-доменные запросы разрешены для всех (*).
Оба домена прописаны в hosts. В продакшене будут прописаны в DNS. Разрешения CORS установлены на обоих серверах, код показан ниже.
При первом открытии index.html на обоих серверах в браузере Chrome получаю ошибку сертификата, но после разрешения ресурса, страница открывается и далее работает. Хотелось бы чтобы она открывалась без этой ошибки и необходимости разрешения.
При загрузке файла на второй сервер в логе браузера (вкладка console) получаю следующие ошибки
Access to XMLHttpRequest at 'https://upserver:8888/upload' from origin 'https://xxx' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
upload.js:73 onreadystatechange Error 0 occurred when trying to upload your file.
upload.js:78 POST https://upserver:8888/upload net::ERR_FAILED
fileUpload @ upload.js:78
(anonymous) @ upload.js:103
upload.js:78 XHR failed loading: POST "https://upserver:8888/upload".
fileUpload @ upload.js:78
(anonymous) @ upload.js:103
Но файл успешно загружается на сервер.
Не могу понять, что ему еще надо, и как исправить эту CORS ошибку?
Код заголовков на upserver:8888
options(Req, Opts) ->
Req1 = cowboy_req:set_resp_header(<<"access-control-allow-methods">>, <<"HEAD, OPTIONS, GET, PUT, POST">>, Req),
Req2 = cowboy_req:set_resp_header(<<"access-control-allow-headers">>, <<"Origin, X-Requested-With, Content-Type,
Accept, x-client-key, x-client-token, x-client-secret">>, Req1),
Req3 = cowboy_req:set_resp_header(<<"access-control-allow-origin">>, <<$*>>, Req2),
{ok, Req3, Opts}.
init(Req, Opts) ->
case cowboy_req:method(Req) of
<<"POST">> ->
{ok, Req1, Opts1} = options(Req, Opts),
{ok, Headers, Req2} = cowboy_req:read_part(Req1),
{ok, Data, Req3} = cowboy_req:read_part_body(Req2),
{file, <<"upfile">>, Filename, ContentType} = cow_multipart:form_data(Headers),
io:format("Received file ~p of content-type ~p as follow:~n~p~n~n", [Filename, ContentType, Data]),
Filepath = filename:join([code:priv_dir("upserver"), "upload", Filename]),
file:write_file(Filepath, Data),
{ok, Req3, Opts1};
_ ->
io:format("Method=~p~n",[cowboy_req:method(Req)]),
options(Req, Opts)
end.
Код запроса на клиенте
function fileUpload(blob){
var filename="test.png";
var file=new File([blob],filename,{type:"image/png"});
var formData = new FormData();
formData.append('upfile', file, filename);
const xhr = new XMLHttpRequest();
xhr.fileinfo = {'filename': filename};
xhr.enctype = "multipart/form-data";
xhr.overrideMimeType('multipart/form-data');
// эта функция работает без ошибок и сообщений
xhr.open("POST", "https://upserver:8888/upload", true);
// Это не помогло, бесполезно, поэтому закоментировано
// xhr.setRequestHeader("Access-Control-Allow-Origin","https://upserver:8888");
// xhr.setRequestHeader("Access-Control-Request-Header","X-Requested-With");
// Это сообщение показано в логе, смотрите лог, Error = xhr.status = 0, вместо 200
xhr.onreadystatechange = function() {
if (xhr.status == 200) {
console.log("onreadystatechange Uploaded!");
} else {
console.log("onreadystatechange Error " + xhr.status + " occurred when trying to upload your file.");
}
};
// здесь выдается сообщение об ошибке CORS
xhr.send(formData);
// В результате, formData успешно передается и правильно сохраняется на сервере, несмотря на все эти ошибки!
}
На стороне первого сервера https://xxx в конфигурации сайта под Nginx прописана следующая конфигурация
server {
listen 443 ssl;
listen [::]:443 ssl;
configuration.
root /var/www/https;
index index.html index.htm index.nginx-debian.html;
server_name xxx;
ssl_certificate /etc/nginx/xxx-list.crt;
ssl_certificate_key /etc/nginx/xxx.key;
location / {
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' 'https://yyy:8888';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Content-Type' 'text/plain charset=UTF-8';
add_header 'Content-Length' 0;
return 204;
}
if ($request_method = 'POST') {
add_header 'Access-Control-Allow-Origin' 'https://upserver:8888';
# add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
}
if ($request_method = 'GET') {
add_header 'Access-Control-Allow-Origin' '*';
# add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
}
try_files $uri $uri/ =404;
}
Видно, что кросс-доменные запросы разрешены для второго сервера upserver:8888
Вроде бы, везде всё настроено белее менее правильно, но ошибки мне очень не нравятся.
Хотелось бы разобраться, что не так, и избавиться от ошибок.