使用ABAP CL_HTTP_CLIENT类消费OData服务时,如何避免CSRF令牌验证失败错误

使用CL_HTTP_CLIENT测试消费OData会出现:CSRF token validation failed

解决办法如下:

1.需要两个创建两个cl_http_client

2.第一个cl_http_client用get获取token和cookies

3.第二个cl_http_client用前面获取的token和cookies来执行post操作

直接上代码:

DATA: lo_http_client   TYPE REF TO if_http_client,  "第一个cl_http_client
      lo_http_client1   TYPE REF TO if_http_client, "第二个cl_http_client
      lv_service       TYPE string,
      lv_result        TYPE string,
      lv_csrf          TYPE string,
      lt_cookies       TYPE tihttpcki,
      lo_ixml          TYPE REF TO if_ixml,
      lo_streamfactory TYPE REF TO if_ixml_stream_factory,
      lo_istream       TYPE REF TO if_ixml_istream,
      lo_document      TYPE REF TO if_ixml_document,
      lo_parser        TYPE REF TO if_ixml_parser.

lv_service = 'http://*****.*****.com:8800/sap/opu/odata/SAP/ZODATA_TEST_SRV/ZWERKSSet'.  "URL

"第一个cl_http_client使用GET获取token和cookies
cl_http_client=>create_by_url(
  EXPORTING
    url                = lv_service
  IMPORTING
    client             = lo_http_client
  EXCEPTIONS
    argument_not_found = 1
    plugin_not_active  = 2
    internal_error     = 3
    OTHERS             = 4 ).

lo_http_client->propertytype_logon_popup = lo_http_client->co_disabled.
CALL METHOD lo_http_client->authenticate(
  EXPORTING
*   client   = ''
*   proxy_authentication = 'X'
    username = '*******'      "账户
    password = '*******'      "密码
*   LANGUAGE = 'E'
               ).
CALL METHOD lo_http_client->request->set_header_field
  EXPORTING
    name  = 'Content-Type'
    value = 'application/JSON; charset=utf-8'.

CALL METHOD lo_http_client->request->set_header_field
  EXPORTING
    name  = 'x-csrf-token'
    value = 'Fetch'.

CALL METHOD lo_http_client->request->set_method( 'GET' ).

lo_http_client->send(
  EXCEPTIONS
    http_communication_failure = 1
    http_invalid_state         = 2 ).

lo_http_client->receive(
  EXCEPTIONS
    http_communication_failure = 1
    http_invalid_state         = 2
    http_processing_failed     = 3 ).

CLEAR lv_result .
lv_result = lo_http_client->response->get_cdata( ).
lv_csrf  = lo_http_client->response->get_header_field( NAME = 'x-csrf-token' ).       "获取token
lo_http_client->response->get_cookies( CHANGING cookies = lt_cookies ).               "获取cookies
lo_ixml = cl_ixml=>create( ).
BREAK-POINT.

lo_streamfactory = lo_ixml->create_stream_factory( ).
lo_istream = lo_streamfactory->create_istream_string(
                                 lv_result ).
lo_document = lo_ixml->create_document( ).
lo_parser = lo_ixml->create_parser(
                       stream_factory = lo_streamfactory
                       istream        = lo_istream
                       document       = lo_document ).
lo_parser->parse( ).
CALL METHOD lo_http_client->close.

"第二个cl_http_client用前面获取的token和cookies来执行POST
cl_http_client=>create_by_url(
  EXPORTING
    url                = lv_service
  IMPORTING
    client             = lo_http_client1
  EXCEPTIONS
    argument_not_found = 1
    plugin_not_active  = 2
    internal_error     = 3
    OTHERS             = 4 ).
lo_http_client1->propertytype_logon_popup = lo_http_client->co_disabled.
CALL METHOD lo_http_client1->authenticate(
  EXPORTING
*   client   = ''
*   proxy_authentication = 'X'
    username = '*******'      "账户
    password = '*******'      "密码
*   LANGUAGE = 'E'
               ).
CALL METHOD lo_http_client1->request->set_header_field
  EXPORTING
    name  = 'Content-Type'
    value = 'application/JSON; charset=utf-8'.

CALL METHOD lo_http_client1->request->set_header_field
  EXPORTING
    name  = 'x-csrf-token'
    value = lv_csrf.                "使用第一个cl_http_clien获取的token

"设置cookies
LOOP AT lt_cookies ASSIGNING FIELD-SYMBOL(<cookie>).
      lo_http_client1->request->set_cookie( name = <cookie>-name
                                           value = <cookie>-value ).
ENDLOOP.

CALL METHOD lo_http_client1->request->set_method( 'POST' ).

DATA lv_json TYPE string.
DATA: len TYPE i .
lv_json =  '{"Werks": "7777", "Active": true}'.          "这边键值要注意,键第一个字母大写,其他小写
len = strlen( lv_json ) .

CALL METHOD lo_http_client1->request->set_cdata
  EXPORTING
    data   = lv_json
    offset = 0
    length = len.

lo_http_client1->send(
  EXCEPTIONS
    http_communication_failure = 1
    http_invalid_state         = 2 ).

lo_http_client1->receive(
  EXCEPTIONS
    http_communication_failure = 1
    http_invalid_state         = 2
    http_processing_failed     = 3 ).

CLEAR lv_result .
lv_result = lo_http_client1->response->get_cdata( ).
lo_ixml = cl_ixml=>create( ).
BREAK-POINT.

lo_streamfactory = lo_ixml->create_stream_factory( ).
lo_istream = lo_streamfactory->create_istream_string(
                                 lv_result ).
lo_document = lo_ixml->create_document( ).
lo_parser = lo_ixml->create_parser(
                       stream_factory = lo_streamfactory
                       istream        = lo_istream
                       document       = lo_document ).
lo_parser->parse( ).
CALL METHOD lo_http_client1->close.

 

如下是大佬直接封装的类,膜拜一下,原文地址:http://blog.itpub.net/24475491/viewspace-2717093/

CLASS zcl_odata_tool DEFINITION
  PUBLIC
  FINAL
  CREATE PUBLIC .
  PUBLIC SECTION.
    CLASS-METHODS get_csrf_token_and_cookie
      EXPORTING
        !et_cookies TYPE tihttpcki
        !ev_token TYPE string .
    CLASS-METHODS create_opp
      IMPORTING
        !iv_token TYPE string
        !it_cookies TYPE tihttpcki .
  PROTECTED SECTION.
  PRIVATE SECTION.ENDCLASS.CLASS ZCL_ODATA_TOOL IMPLEMENTATION.
  METHOD create_opp.
    DEFINE insert_line.
      lv_body = lv_body && &1.
      lv_body = lv_body && cl_abap_char_utilities=>newline.
    END-OF-DEFINITION.
    DATA:lo_http_client TYPE REF TO if_http_client,
             lv_status      TYPE i,
             lt_fields      TYPE tihttpnvp,
             lv_sysubrc     TYPE sysubrc.
    CALL METHOD cl_http_client=>create_by_url
      EXPORTING
        url                = ''
      IMPORTING
        client             = lo_http_client
      EXCEPTIONS
        argument_not_found = 1
        plugin_not_active  = 2
        internal_error     = 3
        OTHERS             = 4.
    ASSERT sy-subrc = 0.
    lo_http_client->propertytype_accept_cookie = if_http_client=>co_enabled.
    CALL METHOD lo_http_client->request->set_method( if_http_request=>co_request_method_post ).
    lo_http_client->request->set_header_field( name = 'Content-Type' value = 'multipart/mixed; boundary=batch_1' ).
    lo_http_client->request->set_header_field( name = 'x-csrf-token' value = iv_token ).
    lo_http_client->request->set_header_field( name = 'Authorization' value = 'your basic authentication code' ).
    LOOP AT it_cookies ASSIGNING FIELD-SYMBOL(<cookie>).
      lo_http_client->request->set_cookie( name = <cookie>-name
                                           value = <cookie>-value ).
    ENDLOOP.
    "这个使用的是name = 'Content-Type' value = 'multipart/mixed; boundary=batch_1'
    "用application/JSON; charset=utf-8就不用那么麻烦了
    DATA: lv_body TYPE string.
    insert_line '--batch_1'.
    insert_line 'Content-Type: multipart/mixed; boundary=changeset_1'.
    lv_body = lv_body && cl_abap_char_utilities=>cr_lf.*
    insert_line '--changeset_1'.
    insert_line 'Content-Type: application/http'.
    insert_line 'Content-Transfer-Encoding: binary'.
    lv_body = lv_body && cl_abap_char_utilities=>cr_lf.
    insert_line 'POST OpportunityCollection HTTP/1.1'.
    insert_line 'Content-Length: 5000'.
    insert_line 'Accept: application/json'.
    insert_line 'Content-Type: application/json'.
    lv_body = lv_body && cl_abap_char_utilities=>cr_lf.
    insert_line '{'.
    insert_line '"AccountID": "8000018122",'.
    insert_line '"OwnerID": "8000018122",'.
    insert_line `"Name": {"content": "Testing ticket creation via OData Jerry1"}`.
    insert_line '}'.
    insert_line '--changeset_1--'.
    lv_body = lv_body && cl_abap_char_utilities=>cr_lf.
    insert_line '--batch_1--'.
    lo_http_client->request->set_cdata( data = lv_body ).

    CALL METHOD lo_http_client->send
      EXCEPTIONS
        http_communication_failure = 1
        http_invalid_state         = 2
        http_processing_failed     = 3.
    ASSERT sy-subrc = 0.
    CALL METHOD lo_http_client->receive
      EXCEPTIONS
        http_communication_failure = 1
        http_invalid_state         = 2
        http_processing_failed     = 3.
    IF sy-subrc <> 0.
      CALL METHOD lo_http_client->get_last_error
        IMPORTING
          code    = lv_sysubrc
          message = DATA(ev_message).
      WRITE: / 'error occurred during receive data' COLOR COL_NEGATIVE.
      RETURN.
    ENDIF.
    DATA(lv_json) = lo_http_client->response->get_cdata( ).
    WRITE:/ lv_json.
  ENDMETHOD.
  METHOD get_csrf_token_and_cookie.
    DATA:  lo_http_client TYPE REF TO if_http_client,
           lv_status      TYPE i,
           lt_fields      TYPE tihttpnvp,
           lv_sysubrc     TYPE sysubrc.
    CALL METHOD cl_http_client=>create_by_url
      EXPORTING
        url                = ''
      IMPORTING
        client             = lo_http_client
      EXCEPTIONS
        argument_not_found = 1
        plugin_not_active  = 2
        internal_error     = 3
        OTHERS             = 4.
    ASSERT sy-subrc = 0.
    lo_http_client->propertytype_accept_cookie = if_http_client=>co_enabled.
    CALL METHOD lo_http_client->request->set_method( if_http_request=>co_request_method_get ).
    lo_http_client->request->set_header_field( name = 'x-csrf-token' value = 'Fetch' ).
    lo_http_client->request->set_header_field( name = 'Accept' value = 'application/json' ).
    lo_http_client->request->set_header_field( name = 'Content-Type' value = 'application/json' ).
    lo_http_client->request->set_header_field( name = 'Authorization' value = 'Your basic authentication' ).
    CALL METHOD lo_http_client->send
      EXCEPTIONS
        http_communication_failure = 1
        http_invalid_state         = 2
        http_processing_failed     = 3.
    ASSERT sy-subrc = 0.
    CALL METHOD lo_http_client->receive
      EXCEPTIONS
        http_communication_failure = 1
        http_invalid_state         = 2
        http_processing_failed     = 3.
    IF sy-subrc <> 0.
      CALL METHOD lo_http_client->get_last_error
        IMPORTING
          code    = lv_sysubrc
          message = DATA(ev_message).
      WRITE: / 'Error when getting token:', ev_message.
      RETURN.
    ENDIF.
    lo_http_client->response->get_header_fields( CHANGING fields = lt_fields ).
    READ TABLE lt_fields ASSIGNING FIELD-SYMBOL(<field>) WITH KEY name = 'x-csrf-token'.
    ev_token = <field>-value.
    lo_http_client->response->get_cookies( CHANGING cookies = et_cookies ).
    lo_http_client->close( ).
  ENDMETHOD.
ENDCLASS.

调用:

zcl_odata_tool=>get_csrf_token_and_cookie( IMPORTING et_cookies = DATA(lt_cookie)
                                                     ev_token = DATA(lv_token) ).
zcl_odata_tool=>create_opp( iv_token = lv_token it_cookies = lt_cookie ).

 

posted on 2022-02-07 11:01  seven1314pp  阅读(1402)  评论(0)    收藏  举报