Làm cách nào để bỏ qua yêu cầu OPTIONS trước khi khởi hành?


92

Tôi đã phát triển một ứng dụng PhoneGap hiện đang được chuyển đổi thành một trang web di động. Mọi thứ hoạt động trơn tru bên cạnh một trục trặc nhỏ. Tôi sử dụng API của bên thứ ba nhất định thông qua yêu cầu ĐĂNG, hoạt động tốt trong ứng dụng, nhưng không thành công trong phiên bản trang web dành cho thiết bị di động.

Sau khi xem xét kỹ hơn, có vẻ như AngularJS (tôi đoán là trình duyệt thực sự) đầu tiên gửi một yêu cầu OPTIONS. Hôm nay tôi đã học được rất nhiều về CORS, nhưng dường như tôi không thể tìm ra cách tắt nó hoàn toàn. Tôi không có quyền truy cập vào API đó (vì vậy các thay đổi ở phía đó là không thể), nhưng họ đã thêm miền tôi đang làm việc vào tiêu đề Access-Control-Allow-Origin của họ.

Đây là mã tôi đang nói về:

        var request = {
                language: 'fr',
                barcodes: [
                    {
                        barcode: 'somebarcode',
                        description: 'Description goes here'
                    }
                ]
            };
        }
        var config = {
            headers: { 
                'Cache-Control': 'no-cache',
                'Content-Type': 'application/json'
            }
        };
        $http.post('http://somedomain.be/trackinginfo', request, config).success(function(data, status) {
            callback(undefined, data);
        }).error(function(data, status) {
            var err = new Error('Error message');
            err.status = status;
            callback(err);
        });

Làm cách nào để ngăn trình duyệt (hoặc AngularJS) gửi yêu cầu TÙY CHỌN đó và bỏ qua yêu cầu ĐĂNG thực tế? Tôi đang sử dụng AngularJS 1.2.0.

Cảm ơn trước.

Câu trả lời:


100

Preflight đang được kích hoạt bởi Loại nội dung của bạn application/json. Cách đơn giản nhất để ngăn chặn điều này là đặt Loại-Nội dung text/plaintrong trường hợp của bạn. application/x-www-form-urlencoded& multipart/form-dataLoại-Nội dung cũng được chấp nhận, nhưng tất nhiên bạn cần phải định dạng trọng tải yêu cầu của mình một cách thích hợp.

Nếu bạn vẫn nhìn thấy ánh sáng trước sau khi thực hiện thay đổi này, thì Angular có thể đang thêm tiêu đề X vào yêu cầu.

Hoặc bạn có thể có các tiêu đề (Ủy quyền, Kiểm soát bộ nhớ cache ...) sẽ kích hoạt nó, hãy xem:


9
Đây là câu trả lời chính xác - tiêu đề Content-Type và Cache-Control của bạn đang kích hoạt yêu cầu preflight. GET đơn giản với Loại nội dung là văn bản / thuần túy và một số loại khác là những cách duy nhất để kích hoạt một yêu cầu không được đánh dấu trước. Xem: developer.mozilla.org/en-US/docs/HTTP/…
Jeff Hubbard

À vâng, quên mất Cache-Control.
Ray Nicholus

15
Một tiêu đề tùy chỉnh cũng sẽ kích hoạt preflight.
Sébastien Deprez

1
Thay đổi loại nội dung để ngăn bài kiểm tra TÙY CHỌN không phải là câu trả lời. Loại nội dung phải khớp với loại nội dung bất kể
ekerner

nếu đó là trình duyệt ném và trong phần phụ trợ, phương thức Http OPTIONS bị chặn, nó có ảnh hưởng gì không như trình duyệt sẽ không gọi API tương ứng cho POST / PUT vì OPTIONS không thành công?
P Satish Patro

16

Như những gì Ray đã nói, bạn có thể ngăn chặn nó bằng cách sửa đổi tiêu đề nội dung như -

 $http.defaults.headers.post["Content-Type"] = "text/plain";

Ví dụ -

angular.module('myApp').factory('User', ['$resource','$http',
    function($resource,$http){
        $http.defaults.headers.post["Content-Type"] = "text/plain";
        return $resource(API_ENGINE_URL+'user/:userId', {}, {
            query: {method:'GET', params:{userId:'users'}, isArray:true},
            getLoggedIn:{method:'GET'}
        });
    }]);

Hoặc trực tiếp gọi -

var req = {
 method: 'POST',
 url: 'http://example.com',
 headers: {
   'Content-Type': 'text/plain'
 },
 data: { test: 'test' }
}

$http(req).then(function(){...}, function(){...});

Thao tác này sẽ không gửi bất kỳ yêu cầu lựa chọn trước chuyến bay nào.

LƯU Ý: Yêu cầu không được có bất kỳ thông số tiêu đề tùy chỉnh nào, Nếu tiêu đề yêu cầu chứa bất kỳ tiêu đề tùy chỉnh nào thì trình duyệt sẽ thực hiện yêu cầu trước chuyến bay, bạn không thể tránh nó.


1
Tôi nên làm như thế nào chỉ với $http?
learningnercys

Cảm ơn, điều đó tương tự như những gì tôi đã làm. Những thay đổi duy nhất là phương thức GETvà một tiêu đề bổ sung Authorization. Nhưng vẫn gửi preflight.
learningnercys

1
Bạn có thể dán yêu cầu của bạn ở đây? như cuộn tròn hay gì đó? Có thể do tiêu đề Ủy quyền, hãy thử xóa nó và sau đó thử. Nếu bạn đang gửi tiêu đề tùy chỉnh thì angle sẽ gửi yêu cầu trước chuyến bay.
vivex

pastebin.com/vRDeFiH2 Đầu tiên là yêu cầu đến $ http và thứ hai là một yêu cầu xây dựng giá trị nó bằng cách đưa thư :)
learnercys

2

Khi thực hiện một số loại yêu cầu AJAX trên nhiều miền, các trình duyệt hiện đại hỗ trợ CORS sẽ chèn thêm một yêu cầu "preflight" để xác định xem chúng có quyền thực hiện hành động hay không. Từ truy vấn mẫu:

$http.get( https://example.com/api/v1/users/’ +userId,
  {params:{
           apiKey:’34d1e55e4b02e56a67b0b66
          }
  } 
);

Kết quả của đoạn này, chúng ta có thể thấy rằng địa chỉ đã được gửi hai yêu cầu (OPTIONS và GET). Phản hồi từ máy chủ bao gồm các tiêu đề xác nhận quyền truy vấn GET. Nếu máy chủ của bạn không được định cấu hình để xử lý yêu cầu OPTIONS đúng cách, các yêu cầu của máy khách sẽ không thành công. Ví dụ:

Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers: accept, origin, x-requested-with, content-type
Access-Control-Allow-Methods: DELETE
Access-Control-Allow-Methods: OPTIONS
Access-Control-Allow-Methods: PUT
Access-Control-Allow-Methods: GET
Access-Control-Allow-Methods: POST
Access-Control-Allow-Orgin: *
Access-Control-Max-Age: 172800
Allow: PUT
Allow: OPTIONS
Allow: POST
Allow: DELETE
Allow: GET

2

Tôi nghĩ cách tốt nhất là kiểm tra xem yêu cầu có thuộc loại "OPTIONS" trả lại 200 từ kho trung gian hay không. Nó đã làm việc cho tôi.

express.use('*',(req,res,next) =>{
      if (req.method == "OPTIONS") {
        res.status(200);
        res.send();
      }else{
        next();
      }
    });

Nó hoạt động nhưng trong OWASP, bạn không nên để lộ OPTIONS. Bạn chặn thời tiết nó trong dịch vụ phụ trợ / được lưu trữ (Nginx, Apache), v.v.
P Satish Patro

0

Preflight là một tính năng bảo mật web được triển khai bởi trình duyệt. Đối với Chrome, bạn có thể tắt tất cả bảo mật web bằng cách thêm cờ --disable-web-security.

Ví dụ: "C: \ Program Files \ Google \ Chrome \ Application \ chrome.exe" --disable-web-security --user-data-dir = "C: \ newChromeSettingsWithoutSecurity". Đầu tiên bạn có thể tạo một phím tắt mới của chrome, vào thuộc tính của nó và thay đổi mục tiêu như trên. Điều này sẽ giúp ích!


Bạn không thể thực sự mong đợi OP sẽ nói với khách hàng của mình tắt bảo mật trình duyệt chỉ để kích hoạt một tính năng, đúng không ?!
svarog

@svarog điều này chủ yếu dành cho mục đích nhà phát triển, chủ yếu là trên máy chủ sản xuất, bạn sẽ không gặp phải vấn đề này.
Arijit Patra

nếu đó là trình duyệt ném và trong phần phụ trợ, phương thức Http OPTIONS bị chặn, nó có ảnh hưởng gì không như trình duyệt sẽ không gọi API tương ứng cho POST / PUT vì OPTIONS không thành công?
P Satish Patro

-2

việc đặt loại nội dung thành không xác định sẽ làm cho javascript chuyển dữ liệu tiêu đề Như nó vốn có và ghi quá nhiều cấu hình tiêu đề $ httpProvider góc cạnh mặc định. Tài liệu Angular $ http

$http({url:url,method:"POST", headers:{'Content-Type':undefined}).then(success,failure);
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.