使用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 ).